diff --git a/.gitignore b/.gitignore
index 8496583..3424f7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -243,6 +243,7 @@
 /ios/third_party/earl_grey2/src
 /ios/third_party/edo/src
 /ios/third_party/gtx/src
+/ios/third_party/lottie/src
 /ios/third_party/material_components_ios/src
 /ios/third_party/material_font_disk_loader_ios/src
 /ios/third_party/material_internationalization_ios/src
diff --git a/AUTHORS b/AUTHORS
index 6f3ba06..f0d04a1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -552,6 +552,7 @@
 Jesus Sanchez-Palencia <jesus.sanchez-palencia.fernandez.fil@intel.com>
 Jiadong Chen <chenjiadong@huawei.com>
 Jiadong Zhu <jiadong.zhu@linaro.org>
+Jiahao Lu <lujjjh@gmail.com>
 Jiahe Zhang <jiahe.zhang@intel.com>
 Jiajia Qin <jiajia.qin@intel.com>
 Jiajie Hu <jiajie.hu@intel.com>
diff --git a/DEPS b/DEPS
index 5f5cde9..8f59ab183 100644
--- a/DEPS
+++ b/DEPS
@@ -301,7 +301,7 @@
   # 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': '3b2d9e4bf66832436743423ef3d9938c87459bbd',
+  'skia_revision': '8d4f03e9239ad99cf248c235421bd2eb3c43980c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -309,7 +309,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '72e2ce69dc0efbdc32f6176d8d8271b71018e2bc',
+  'angle_revision': '202fcb8d854a92bc18ac958bb7f863977bf7cb20',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -372,7 +372,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': 'c996ebbd3d54112b5b730e9af212ce6b55ba61ef',
+  'catapult_revision': '2b857d73ffd0ea3eedcded1ba16f14a80185e94f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -416,7 +416,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': 'ccd369861f8866fbd9d62dd9c159f56843e0ead2',
+  'dawn_revision': 'd6d30f425653576f9a3da43f462a55327323b30f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -428,7 +428,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libexpat
   # and whatever else without interference from each other.
-  'libexpat_revision': '53fbdf5b8925a426e1b41a9e09b833986b87524e',
+  'libexpat_revision': '441f98d02deafd9b090aea568282b28f66a50e36',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling wuffs
   # and whatever else without interference from each other.
@@ -591,7 +591,7 @@
     'packages': [
       {
         'package': 'chromium/third_party/rust_src',
-        'version': 'version:2@2022-11-01',
+        'version': 'version:2@2022-11-18',
       },
     ],
     'dep_type': 'cipd',
@@ -811,7 +811,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    '568be322b4c9e1c03e37c6996285d68a0b90b38c',
+    'baac8c9bd49b618c2a91b07d5195660133c356fb',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -834,6 +834,11 @@
       'condition': 'checkout_ios',
   },
 
+  'src/ios/third_party/lottie/src': {
+      'url': Var('chromium_git') + '/external/github.com/airbnb/lottie-ios.git' + '@' + '4a4367659c0b8576d4a106669ff2ba129026085f',
+      'condition': 'checkout_ios',
+  },
+
   'src/ios/third_party/material_components_ios/src': {
       'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '515ba2f70ecdeb0f596697f4d8266892a516bb2e',
       'condition': 'checkout_ios',
@@ -1210,7 +1215,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '06404255922ceb03054273b5c35fe2b67cea41f4',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e2954831c532808781d2386905d80f84e96f6b38',
       'condition': 'checkout_chromeos',
   },
 
@@ -1244,7 +1249,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '3bed02a8b26e568827d040e40985dbc0884f183e',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '99452bce3822b5f10dcbda92d7d6568f417b92dc',
     'condition': 'checkout_src_internal',
   },
 
@@ -1659,7 +1664,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '51908f273fa158b58c6336afa93b65838c6ff3cf',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4f6803dfe01e8e9f05957329f0475044dc658990',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1841,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' + '@' + '5bc45b0d4f546434c3ca75847d15c40e4425d2de',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '39eb8086a4f030c8405f93ef770a6bfe8ab7fc55',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + 'dd35e244cec8b3af022ac92b2185465a422f2eec',
@@ -1955,7 +1960,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'dPtbu2LkFG30wC5QbPnPVuVRjP7mZG6gadfnS2XzVqcC',
+        'version': 'itqlU3isswJBaFObM0FA_o6f714I6FXCvL_XxliQo4oC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 5c60a80d..a8642e6 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -3228,10 +3228,9 @@
         # Restore sys.path to what it was before.
         sys.path = original_sys_path
 
-    return checkstyle.RunCheckstyle(
+    return checkstyle.run_presubmit(
         input_api,
         output_api,
-        'tools/android/checkstyle/chromium-style-5.0.xml',
         files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
 
 
diff --git a/ash/components/arc/intent_helper/OWNERS b/ash/components/arc/intent_helper/OWNERS
index 52656497..8aa79d75 100644
--- a/ash/components/arc/intent_helper/OWNERS
+++ b/ash/components/arc/intent_helper/OWNERS
@@ -3,4 +3,4 @@
 
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-per-file *_mojom_traits*.*=file://components/arc/mojom/ARC_SECURITY_OWNERS
+per-file *_mojom_traits*.*=file://chromeos/SECURITY_OWNERS
diff --git a/ash/components/arc/test/OWNERS b/ash/components/arc/test/OWNERS
index 96e956b..c7e8cae 100644
--- a/ash/components/arc/test/OWNERS
+++ b/ash/components/arc/test/OWNERS
@@ -1,2 +1,2 @@
 per-file fake_*_instance.*=*
-per-file payment_app_service_test_support.cc=file://components/arc/pay/OWNERS
+per-file payment_app_service_test_support.cc=file://ash/components/arc/pay/OWNERS
diff --git a/ash/components/phonehub/app_stream_launcher_data_model.cc b/ash/components/phonehub/app_stream_launcher_data_model.cc
index 9987bc37..1a7c257 100644
--- a/ash/components/phonehub/app_stream_launcher_data_model.cc
+++ b/ash/components/phonehub/app_stream_launcher_data_model.cc
@@ -4,7 +4,8 @@
 
 #include "ash/components/phonehub/app_stream_launcher_data_model.h"
 
-namespace ash::phonehub {
+namespace ash {
+namespace phonehub {
 
 AppStreamLauncherDataModel::AppStreamLauncherDataModel() = default;
 
@@ -33,4 +34,29 @@
   should_show_app_stream_launcher_ = false;
 }
 
-}  // namespace ash::phonehub
+void AppStreamLauncherDataModel::SetAppList(
+    const std::vector<Notification::AppMetadata>& streamable_apps) {
+  apps_list_ = streamable_apps;
+
+  apps_list_sorted_by_name_ = streamable_apps;
+
+  // Alphabetically sort the app list.
+  std::sort(apps_list_sorted_by_name_.begin(), apps_list_sorted_by_name_.end(),
+            [](const Notification::AppMetadata& a,
+               const Notification::AppMetadata& b) {
+              return a.visible_app_name < b.visible_app_name;
+            });
+}
+
+const std::vector<Notification::AppMetadata>*
+AppStreamLauncherDataModel::GetAppsList() {
+  return &apps_list_;
+}
+
+const std::vector<Notification::AppMetadata>*
+AppStreamLauncherDataModel::GetAppsListSortedByName() {
+  return &apps_list_sorted_by_name_;
+}
+
+}  // namespace phonehub
+}  // namespace ash
diff --git a/ash/components/phonehub/app_stream_launcher_data_model.h b/ash/components/phonehub/app_stream_launcher_data_model.h
index 39563a8..3d4b16c 100644
--- a/ash/components/phonehub/app_stream_launcher_data_model.h
+++ b/ash/components/phonehub/app_stream_launcher_data_model.h
@@ -5,6 +5,8 @@
 #ifndef ASH_COMPONENTS_PHONEHUB_APP_STREAM_LAUNCHER_DATA_MODEL_H_
 #define ASH_COMPONENTS_PHONEHUB_APP_STREAM_LAUNCHER_DATA_MODEL_H_
 
+#include <memory>
+#include "ash/components/phonehub/notification.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
 
@@ -20,6 +22,7 @@
     virtual void OnShouldShowMiniLauncherChanged() = 0;
   };
 
+  AppStreamLauncherDataModel();
   AppStreamLauncherDataModel(const AppStreamLauncherDataModel&) = delete;
   AppStreamLauncherDataModel& operator=(const AppStreamLauncherDataModel&) =
       delete;
@@ -39,14 +42,17 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
- public:
-  AppStreamLauncherDataModel();
+  void SetAppList(
+      const std::vector<Notification::AppMetadata>& streamable_apps);
+  const std::vector<Notification::AppMetadata>* GetAppsList();
+  const std::vector<Notification::AppMetadata>* GetAppsListSortedByName();
 
  private:
   // Indicates if the Mini Launcher should be shown when the status is
   // "phone connected" or not.
   bool should_show_app_stream_launcher_ = false;
-
+  std::vector<Notification::AppMetadata> apps_list_;
+  std::vector<Notification::AppMetadata> apps_list_sorted_by_name_;
   base::ObserverList<Observer> observer_list_;
 };
 
diff --git a/ash/components/phonehub/fake_recent_apps_interaction_handler.cc b/ash/components/phonehub/fake_recent_apps_interaction_handler.cc
index 4aa6a93..5d5500ea 100644
--- a/ash/components/phonehub/fake_recent_apps_interaction_handler.cc
+++ b/ash/components/phonehub/fake_recent_apps_interaction_handler.cc
@@ -56,7 +56,7 @@
 }
 
 void FakeRecentAppsInteractionHandler::SetStreamableApps(
-    const proto::StreamableApps& streamable_apps) {
+    const std::vector<Notification::AppMetadata>& streamable_apps) {
   // TODO(nayebi): Do we need to implement this?
 }
 
diff --git a/ash/components/phonehub/fake_recent_apps_interaction_handler.h b/ash/components/phonehub/fake_recent_apps_interaction_handler.h
index a2bd7b5..63ef3a0 100644
--- a/ash/components/phonehub/fake_recent_apps_interaction_handler.h
+++ b/ash/components/phonehub/fake_recent_apps_interaction_handler.h
@@ -43,7 +43,8 @@
       const Notification::AppMetadata& app_metadata,
       base::Time last_accessed_timestamp) override;
   std::vector<Notification::AppMetadata> FetchRecentAppMetadataList() override;
-  void SetStreamableApps(const proto::StreamableApps& streamable_apps) override;
+  void SetStreamableApps(
+      const std::vector<Notification::AppMetadata>& streamable_apps) override;
 
  private:
   void ComputeAndUpdateUiState();
diff --git a/ash/components/phonehub/icon_decoder.h b/ash/components/phonehub/icon_decoder.h
index 0e18ec9..e2495b9 100644
--- a/ash/components/phonehub/icon_decoder.h
+++ b/ash/components/phonehub/icon_decoder.h
@@ -5,6 +5,7 @@
 #ifndef ASH_COMPONENTS_PHONEHUB_ICON_DECODER_H_
 #define ASH_COMPONENTS_PHONEHUB_ICON_DECODER_H_
 
+#include "ash/components/phonehub/notification.h"
 #include "base/callback.h"
 #include "ui/gfx/image/image.h"
 
diff --git a/ash/components/phonehub/icon_decoder_impl.cc b/ash/components/phonehub/icon_decoder_impl.cc
index 5c144d3..dcc3390 100644
--- a/ash/components/phonehub/icon_decoder_impl.cc
+++ b/ash/components/phonehub/icon_decoder_impl.cc
@@ -14,6 +14,7 @@
 #include "base/callback_forward.h"
 #include "base/containers/flat_map.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/string_number_conversions.h"
 #include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "services/data_decoder/public/cpp/decode_image.h"
 #include "services/data_decoder/public/mojom/image_decoder.mojom.h"
diff --git a/ash/components/phonehub/icon_decoder_impl.h b/ash/components/phonehub/icon_decoder_impl.h
index f3e5c03..cfdb037 100644
--- a/ash/components/phonehub/icon_decoder_impl.h
+++ b/ash/components/phonehub/icon_decoder_impl.h
@@ -8,7 +8,6 @@
 #include "ash/components/phonehub/icon_decoder.h"
 
 #include "ash/components/phonehub/proto/phonehub_api.pb.h"
-#include "ash/components/phonehub/recent_apps_interaction_handler.h"
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "services/data_decoder/public/cpp/data_decoder.h"
@@ -31,7 +30,7 @@
  private:
   friend class IconDecoderImplTest;
   friend class TestDecoderDelegate;
-  friend class RecentAppsInteractionHandlerTest;
+  friend class PhoneStatusProcessorTest;
 
   // Delegate class that decodes icons. Can be overridden in tests.
   class DecoderDelegate {
diff --git a/ash/components/phonehub/phone_hub_manager_impl.cc b/ash/components/phonehub/phone_hub_manager_impl.cc
index 73c752d..c92a891 100644
--- a/ash/components/phonehub/phone_hub_manager_impl.cc
+++ b/ash/components/phonehub/phone_hub_manager_impl.cc
@@ -123,8 +123,7 @@
               ? std::make_unique<RecentAppsInteractionHandlerImpl>(
                     pref_service,
                     multidevice_setup_client,
-                    multidevice_feature_access_manager_.get(),
-                    icon_decoder_.get())
+                    multidevice_feature_access_manager_.get())
               : nullptr),
       app_stream_manager_(std::make_unique<AppStreamManager>()),
       phone_status_processor_(std::make_unique<PhoneStatusProcessor>(
@@ -139,7 +138,9 @@
           phone_model_.get(),
           recent_apps_interaction_handler_.get(),
           pref_service,
-          app_stream_manager_.get())),
+          app_stream_manager_.get(),
+          app_stream_launcher_data_model_.get(),
+          icon_decoder_.get())),
       tether_controller_(
           std::make_unique<TetherControllerImpl>(phone_model_.get(),
                                                  user_action_recorder_.get(),
diff --git a/ash/components/phonehub/phone_status_processor.cc b/ash/components/phonehub/phone_status_processor.cc
index 7b0a6fb..8197f84 100644
--- a/ash/components/phonehub/phone_status_processor.cc
+++ b/ash/components/phonehub/phone_status_processor.cc
@@ -12,6 +12,7 @@
 #include "ash/components/phonehub/do_not_disturb_controller.h"
 #include "ash/components/phonehub/find_my_device_controller.h"
 #include "ash/components/phonehub/icon_decoder.h"
+#include "ash/components/phonehub/icon_decoder_impl.h"
 #include "ash/components/phonehub/message_receiver.h"
 #include "ash/components/phonehub/multidevice_feature_access_manager.h"
 #include "ash/components/phonehub/mutable_phone_model.h"
@@ -22,9 +23,13 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/containers/flat_set.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chromeos/ash/components/multidevice/logging/logging.h"
 #include "chromeos/ash/services/multidevice_setup/public/cpp/prefs.h"
 #include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 #include "components/prefs/pref_service.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/paint_vector_icon.h"
 
 namespace ash {
 namespace phonehub {
@@ -200,7 +205,9 @@
     MutablePhoneModel* phone_model,
     RecentAppsInteractionHandler* recent_apps_interaction_handler,
     PrefService* pref_service,
-    AppStreamManager* app_stream_manager)
+    AppStreamManager* app_stream_manager,
+    AppStreamLauncherDataModel* app_stream_launcher_data_model,
+    IconDecoder* icon_decoder)
     : do_not_disturb_controller_(do_not_disturb_controller),
       feature_status_provider_(feature_status_provider),
       message_receiver_(message_receiver),
@@ -212,7 +219,9 @@
       phone_model_(phone_model),
       recent_apps_interaction_handler_(recent_apps_interaction_handler),
       pref_service_(pref_service),
-      app_stream_manager_(app_stream_manager) {
+      app_stream_manager_(app_stream_manager),
+      app_stream_launcher_data_model_(app_stream_launcher_data_model),
+      icon_decoder_(icon_decoder) {
   DCHECK(do_not_disturb_controller_);
   DCHECK(feature_status_provider_);
   DCHECK(message_receiver_);
@@ -223,6 +232,7 @@
   DCHECK(phone_model_);
   DCHECK(pref_service_);
   DCHECK(app_stream_manager_);
+  DCHECK(icon_decoder_);
 
   message_receiver_->AddObserver(this);
   feature_status_provider_->AddObserver(this);
@@ -365,7 +375,7 @@
   ProcessReceivedNotifications(phone_status_snapshot.notifications());
   SetReceivedPhoneStatusModelStates(phone_status_snapshot.properties());
   if (features::IsEcheSWAEnabled()) {
-    SetStreamableApps(phone_status_snapshot.streamable_apps());
+    GenerateAppListWithIcons(phone_status_snapshot.streamable_apps());
   }
   multidevice_feature_access_manager_
       ->UpdatedFeatureSetupConnectionStatusIfNeeded();
@@ -402,10 +412,61 @@
   MaybeSetPhoneModelName(host_device_with_status.second);
 }
 
-void PhoneStatusProcessor::SetStreamableApps(
+void PhoneStatusProcessor::GenerateAppListWithIcons(
     const proto::StreamableApps& streamable_apps) {
-  if (streamable_apps.apps_size() > 0 && recent_apps_interaction_handler_)
-    recent_apps_interaction_handler_->SetStreamableApps(streamable_apps);
+  if (streamable_apps.apps_size() == 0) {
+    return;
+  }
+  std::unique_ptr<std::vector<IconDecoder::DecodingData>> decoding_data_list =
+      std::make_unique<std::vector<IconDecoder::DecodingData>>();
+  std::hash<std::string> str_hash;
+  gfx::Image image =
+      gfx::Image(CreateVectorIcon(kPhoneHubPhoneIcon, gfx::kGoogleGrey700));
+  std::vector<Notification::AppMetadata> apps_list;
+  for (const auto& app : streamable_apps.apps()) {
+    // TODO(nayebi): AppMetadata is no longer limited to Notification class,
+    // let's move it outside of the Notification class.s2
+    apps_list.emplace_back(Notification::AppMetadata(
+        base::UTF8ToUTF16(app.visible_name()), app.package_name(), image,
+        absl::nullopt,
+        app.icon_styling() ==
+            proto::NotificationIconStyling::ICON_STYLE_MONOCHROME_SMALL_ICON,
+        app.user_id()));
+    std::string key = app.package_name() + base::NumberToString(app.user_id());
+    decoding_data_list->emplace_back(
+        IconDecoder::DecodingData(str_hash(key), app.icon()));
+  }
+
+  icon_decoder_->BatchDecode(std::move(decoding_data_list),
+                             base::BindOnce(&PhoneStatusProcessor::IconsDecoded,
+                                            weak_ptr_factory_.GetWeakPtr(),
+                                            base::OwnedRef(apps_list)));
+}
+
+void PhoneStatusProcessor::IconsDecoded(
+    std::vector<Notification::AppMetadata>& apps_list,
+    std::unique_ptr<std::vector<IconDecoder::DecodingData>> decode_items) {
+  std::hash<std::string> str_hash;
+  for (const IconDecoder::DecodingData& decoding_data : *decode_items) {
+    if (decoding_data.result.IsEmpty())
+      continue;
+    // find the associated app metadata
+    for (auto& app_metadata : apps_list) {
+      std::string key = app_metadata.package_name +
+                        base::NumberToString(app_metadata.user_id);
+      if (decoding_data.id == str_hash(key)) {
+        app_metadata.icon = decoding_data.result;
+        continue;
+      }
+    }
+  }
+  if (recent_apps_interaction_handler_) {
+    recent_apps_interaction_handler_->SetStreamableApps(apps_list);
+  }
+
+  if (features::IsEcheLauncherEnabled() && app_stream_launcher_data_model_) {
+    app_stream_launcher_data_model_->SetAppList(apps_list);
+  }
 }
 
 }  // namespace phonehub
diff --git a/ash/components/phonehub/phone_status_processor.h b/ash/components/phonehub/phone_status_processor.h
index 0911271..2b97dd98 100644
--- a/ash/components/phonehub/phone_status_processor.h
+++ b/ash/components/phonehub/phone_status_processor.h
@@ -7,7 +7,9 @@
 
 #include <google/protobuf/repeated_field.h>
 
+#include "app_stream_launcher_data_model.h"
 #include "ash/components/phonehub/feature_status_provider.h"
+#include "ash/components/phonehub/icon_decoder.h"
 #include "ash/components/phonehub/message_receiver.h"
 #include "ash/components/phonehub/proto/phonehub_api.pb.h"
 #include "chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
@@ -46,7 +48,9 @@
       MutablePhoneModel* phone_model,
       RecentAppsInteractionHandler* recent_apps_interaction_handler,
       PrefService* pref_service,
-      AppStreamManager* app_stream_manager);
+      AppStreamManager* app_stream_manager,
+      AppStreamLauncherDataModel* app_stream_launcher_data_model,
+      IconDecoder* icon_decoder_);
   ~PhoneStatusProcessor() override;
 
   PhoneStatusProcessor(const PhoneStatusProcessor&) = delete;
@@ -71,8 +75,6 @@
       const multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice&
           host_device_with_status) override;
 
-  void SetStreamableApps(const proto::StreamableApps& streamable_apps);
-
   void ProcessReceivedNotifications(
       const RepeatedPtrField<proto::Notification>& notification_protos);
 
@@ -85,6 +87,12 @@
   void SetEcheFeatureStatusReceivedFromPhoneHub(
       proto::FeatureStatus eche_feature_status);
 
+  void GenerateAppListWithIcons(const proto::StreamableApps& streamable_apps);
+
+  void IconsDecoded(
+      std::vector<Notification::AppMetadata>& apps_list,
+      std::unique_ptr<std::vector<IconDecoder::DecodingData>> decode_items);
+
   DoNotDisturbController* do_not_disturb_controller_;
   FeatureStatusProvider* feature_status_provider_;
   MessageReceiver* message_receiver_;
@@ -97,6 +105,8 @@
   RecentAppsInteractionHandler* recent_apps_interaction_handler_;
   PrefService* pref_service_;
   AppStreamManager* app_stream_manager_;
+  AppStreamLauncherDataModel* app_stream_launcher_data_model_;
+  IconDecoder* icon_decoder_;
 
   base::WeakPtrFactory<PhoneStatusProcessor> weak_ptr_factory_{this};
 };
diff --git a/ash/components/phonehub/phone_status_processor_unittest.cc b/ash/components/phonehub/phone_status_processor_unittest.cc
index 44b3332..b2d932f3 100644
--- a/ash/components/phonehub/phone_status_processor_unittest.cc
+++ b/ash/components/phonehub/phone_status_processor_unittest.cc
@@ -10,6 +10,7 @@
 #include <string>
 #include <utility>
 
+#include "ash/components/phonehub/app_stream_launcher_data_model.h"
 #include "ash/components/phonehub/app_stream_manager.h"
 #include "ash/components/phonehub/fake_do_not_disturb_controller.h"
 #include "ash/components/phonehub/fake_feature_status_provider.h"
@@ -19,6 +20,8 @@
 #include "ash/components/phonehub/fake_notification_manager.h"
 #include "ash/components/phonehub/fake_recent_apps_interaction_handler.h"
 #include "ash/components/phonehub/fake_screen_lock_manager.h"
+#include "ash/components/phonehub/icon_decoder.h"
+#include "ash/components/phonehub/icon_decoder_impl.h"
 #include "ash/components/phonehub/mutable_phone_model.h"
 #include "ash/components/phonehub/notification_manager.h"
 #include "ash/components/phonehub/notification_processor.h"
@@ -81,6 +84,41 @@
 };
 
 class PhoneStatusProcessorTest : public testing::Test {
+  class TestDecoderDelegate : public IconDecoderImpl::DecoderDelegate {
+   public:
+    TestDecoderDelegate() = default;
+    ~TestDecoderDelegate() override = default;
+
+    void Decode(const IconDecoder::DecodingData& data,
+                data_decoder::DecodeImageCallback callback) override {
+      pending_callbacks_[data.id] = std::move(callback);
+      CompleteRequest(data.id);
+    }
+
+    void CompleteRequest(const unsigned long id) {
+      SkBitmap test_bitmap;
+      test_bitmap.allocN32Pixels(id % 10, 1);
+      std::move(pending_callbacks_.at(id)).Run(test_bitmap);
+      pending_callbacks_.erase(id);
+    }
+
+    void FailRequest(const unsigned long id) {
+      SkBitmap test_bitmap;
+      std::move(pending_callbacks_.at(id)).Run(test_bitmap);
+      pending_callbacks_.erase(id);
+    }
+
+    void CompleteAllRequests() {
+      for (auto& it : pending_callbacks_)
+        CompleteRequest(it.first);
+      pending_callbacks_.clear();
+    }
+
+   private:
+    base::flat_map<unsigned long, data_decoder::DecodeImageCallback>
+        pending_callbacks_;
+  };
+
  protected:
   PhoneStatusProcessorTest()
       : test_remote_device_(multidevice::CreateRemoteDeviceRefForTest()) {}
@@ -92,7 +130,7 @@
     scoped_feature_list_.InitWithFeatures(
         /*enabled_features=*/{features::kEcheSWA,
                               features::kPhoneHubCameraRoll},
-        /*disabled_features=*/{});
+        /*disabled_features=*/{features::kEcheLauncher});
 
     fake_do_not_disturb_controller_ =
         std::make_unique<FakeDoNotDisturbController>();
@@ -112,6 +150,13 @@
         std::make_unique<multidevice_setup::FakeMultiDeviceSetupClient>();
     fake_recent_apps_interaction_handler_ =
         std::make_unique<FakeRecentAppsInteractionHandler>();
+    icon_decoder_ = std::make_unique<IconDecoderImpl>();
+    icon_decoder_.get()->decoder_delegate_ =
+        std::make_unique<TestDecoderDelegate>();
+    decoder_delegate_ = static_cast<TestDecoderDelegate*>(
+        icon_decoder_.get()->decoder_delegate_.get());
+    app_stream_launcher_data_model_ =
+        std::make_unique<AppStreamLauncherDataModel>();
 
     multidevice_setup::RegisterFeaturePrefs(pref_service_.registry());
   }
@@ -125,7 +170,8 @@
         fake_screen_lock_manager_.get(), fake_notification_processor_.get(),
         fake_multidevice_setup_client_.get(), mutable_phone_model_.get(),
         fake_recent_apps_interaction_handler_.get(), &pref_service_,
-        &app_stream_manager_);
+        &app_stream_manager_, app_stream_launcher_data_model_.get(),
+        icon_decoder_.get());
   }
 
   void InitializeNotificationProto(proto::Notification* notification,
@@ -175,9 +221,12 @@
       fake_multidevice_setup_client_;
   std::unique_ptr<FakeRecentAppsInteractionHandler>
       fake_recent_apps_interaction_handler_;
+  std::unique_ptr<IconDecoderImpl> icon_decoder_;
+  TestDecoderDelegate* decoder_delegate_;
   TestingPrefServiceSimple pref_service_;
   AppStreamManager app_stream_manager_;
   AppStreamManagerObserver app_stream_manager_observer_;
+  std::unique_ptr<AppStreamLauncherDataModel> app_stream_launcher_data_model_;
   std::unique_ptr<PhoneStatusProcessor> phone_status_processor_;
 };
 
@@ -389,6 +438,133 @@
       fake_recent_apps_interaction_handler_->user_states();
   EXPECT_EQ(1u, user_states[0].user_id);
   EXPECT_EQ(true, user_states[0].is_enabled);
+
+  EXPECT_TRUE(app_stream_launcher_data_model_->GetAppsList()->empty());
+}
+
+TEST_F(PhoneStatusProcessorTest,
+       PhoneStatusSnapshotUpdate_AppStreamLauncher_enableded) {
+  scoped_feature_list_.Reset();
+  scoped_feature_list_.InitWithFeatures(
+      /*enabled_features=*/{features::kEcheSWA, features::kPhoneHubCameraRoll,
+                            features::kEcheLauncher},
+      /*disabled_features=*/{});
+  fake_multidevice_setup_client_->SetHostStatusWithDevice(
+      std::make_pair(HostStatus::kHostVerified, test_remote_device_));
+  CreatePhoneStatusProcessor();
+
+  auto expected_phone_properties = std::make_unique<proto::PhoneProperties>();
+  expected_phone_properties->set_notification_mode(
+      proto::NotificationMode::DO_NOT_DISTURB_ON);
+  expected_phone_properties->set_profile_type(
+      proto::ProfileType::DEFAULT_PROFILE);
+  expected_phone_properties->set_notification_access_state(
+      proto::NotificationAccessState::ACCESS_NOT_GRANTED);
+  expected_phone_properties->set_ring_status(
+      proto::FindMyDeviceRingStatus::RINGING);
+  expected_phone_properties->set_battery_percentage(24u);
+  expected_phone_properties->set_charging_state(
+      proto::ChargingState::CHARGING_AC);
+  expected_phone_properties->set_signal_strength(
+      proto::SignalStrength::FOUR_BARS);
+  expected_phone_properties->set_mobile_provider("google");
+  expected_phone_properties->set_connection_state(
+      proto::MobileConnectionState::SIM_WITH_RECEPTION);
+  expected_phone_properties->set_screen_lock_state(
+      proto::ScreenLockState::SCREEN_LOCK_UNKNOWN);
+  proto::CameraRollAccessState* access_state =
+      expected_phone_properties->mutable_camera_roll_access_state();
+  access_state->set_feature_enabled(true);
+  proto::FeatureSetupConfig* feature_setup_config =
+      expected_phone_properties->mutable_feature_setup_config();
+  feature_setup_config->set_feature_setup_request_supported(true);
+  expected_phone_properties->set_eche_feature_status(
+      proto::FeatureStatus::FEATURE_STATUS_SUPPORTED);
+
+  expected_phone_properties->add_user_states();
+  proto::UserState* mutable_user_state =
+      expected_phone_properties->mutable_user_states(0);
+  mutable_user_state->set_user_id(1u);
+  mutable_user_state->set_is_quiet_mode_enabled(false);
+
+  proto::PhoneStatusSnapshot expected_snapshot;
+  expected_snapshot.set_allocated_properties(
+      expected_phone_properties.release());
+  expected_snapshot.add_notifications();
+  InitializeNotificationProto(expected_snapshot.mutable_notifications(0),
+                              /*id=*/0u);
+  auto* streamable_apps = expected_snapshot.mutable_streamable_apps();
+  auto* app = streamable_apps->add_apps();
+  app->set_package_name("pkg1");
+  app->set_visible_name("vis");
+
+  auto* app2 = streamable_apps->add_apps();
+  app2->set_package_name("pkg2");
+  app2->set_visible_name("a_vis");  // Test alphbetical sort.
+
+  // Simulate feature set to enabled and connected.
+  fake_feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected);
+  fake_multidevice_setup_client_->SetFeatureState(
+      Feature::kPhoneHubNotifications, FeatureState::kEnabledByUser);
+
+  // Simulate receiving a proto message.
+  fake_message_receiver_->NotifyPhoneStatusSnapshotReceived(expected_snapshot);
+
+  EXPECT_EQ(1u, fake_notification_manager_->num_notifications());
+  EXPECT_EQ(base::UTF8ToUTF16(test_remote_device_.name()),
+            *mutable_phone_model_->phone_name());
+  EXPECT_TRUE(fake_do_not_disturb_controller_->IsDndEnabled());
+  EXPECT_TRUE(fake_do_not_disturb_controller_->CanRequestNewDndState());
+  EXPECT_EQ(FindMyDeviceController::Status::kRingingOn,
+            fake_find_my_device_controller_->GetPhoneRingingStatus());
+  EXPECT_EQ(
+      MultideviceFeatureAccessManager::AccessStatus::kAvailableButNotGranted,
+      fake_multidevice_feature_access_manager_->GetNotificationAccessStatus());
+  EXPECT_EQ(
+      MultideviceFeatureAccessManager::AccessStatus::kAccessGranted,
+      fake_multidevice_feature_access_manager_->GetCameraRollAccessStatus());
+  EXPECT_TRUE(fake_multidevice_feature_access_manager_
+                  ->GetFeatureSetupRequestSupported());
+  EXPECT_EQ(ScreenLockManager::LockStatus::kUnknown,
+            fake_screen_lock_manager_->GetLockStatus());
+
+  absl::optional<PhoneStatusModel> phone_status_model =
+      mutable_phone_model_->phone_status_model();
+  EXPECT_EQ(PhoneStatusModel::ChargingState::kChargingAc,
+            phone_status_model->charging_state());
+  EXPECT_EQ(24u, phone_status_model->battery_percentage());
+  EXPECT_EQ(u"google",
+            phone_status_model->mobile_connection_metadata()->mobile_provider);
+  EXPECT_EQ(PhoneStatusModel::SignalStrength::kFourBars,
+            phone_status_model->mobile_connection_metadata()->signal_strength);
+  EXPECT_EQ(PhoneStatusModel::MobileStatus::kSimWithReception,
+            phone_status_model->mobile_status());
+
+  EXPECT_EQ(ash::multidevice_setup::EcheSupportReceivedFromPhoneHub::kSupported,
+            GetEcheSupportReceivedFromPhoneHub());
+
+  // Change feature status to disconnected.
+  fake_feature_status_provider_->SetStatus(
+      FeatureStatus::kEnabledButDisconnected);
+
+  EXPECT_EQ(0u, fake_notification_manager_->num_notifications());
+  EXPECT_EQ(base::UTF8ToUTF16(test_remote_device_.name()),
+            *mutable_phone_model_->phone_name());
+  EXPECT_FALSE(mutable_phone_model_->phone_status_model().has_value());
+
+  std::vector<RecentAppsInteractionHandler::UserState> user_states =
+      fake_recent_apps_interaction_handler_->user_states();
+  EXPECT_EQ(1u, user_states[0].user_id);
+  EXPECT_EQ(true, user_states[0].is_enabled);
+
+  EXPECT_EQ(2u,
+            app_stream_launcher_data_model_->GetAppsListSortedByName()->size());
+  EXPECT_EQ(u"a_vis", app_stream_launcher_data_model_->GetAppsListSortedByName()
+                          ->at(0)
+                          .visible_app_name);
+  EXPECT_EQ(u"vis", app_stream_launcher_data_model_->GetAppsListSortedByName()
+                        ->at(1)
+                        .visible_app_name);
 }
 
 TEST_F(PhoneStatusProcessorTest, PhoneStatusUpdate) {
diff --git a/ash/components/phonehub/recent_apps_interaction_handler.h b/ash/components/phonehub/recent_apps_interaction_handler.h
index af19f97..29dc9a5 100644
--- a/ash/components/phonehub/recent_apps_interaction_handler.h
+++ b/ash/components/phonehub/recent_apps_interaction_handler.h
@@ -71,7 +71,7 @@
   virtual std::vector<Notification::AppMetadata>
   FetchRecentAppMetadataList() = 0;
   virtual void SetStreamableApps(
-      const proto::StreamableApps& streamable_apps) = 0;
+      const std::vector<Notification::AppMetadata>& streamable_apps) = 0;
 
  protected:
   RecentAppsInteractionHandler();
diff --git a/ash/components/phonehub/recent_apps_interaction_handler_impl.cc b/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
index 30190f6..58f9256a 100644
--- a/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
+++ b/ash/components/phonehub/recent_apps_interaction_handler_impl.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "ash/components/phonehub/icon_decoder.h"
 #include "ash/components/phonehub/notification.h"
 #include "ash/components/phonehub/pref_names.h"
 #include "ash/components/phonehub/proto/phonehub_api.pb.h"
@@ -46,13 +45,10 @@
 RecentAppsInteractionHandlerImpl::RecentAppsInteractionHandlerImpl(
     PrefService* pref_service,
     multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
-    MultideviceFeatureAccessManager* multidevice_feature_access_manager,
-    IconDecoder* icon_decoder)
+    MultideviceFeatureAccessManager* multidevice_feature_access_manager)
     : pref_service_(pref_service),
       multidevice_setup_client_(multidevice_setup_client),
-      multidevice_feature_access_manager_(multidevice_feature_access_manager),
-      icon_decoder_(icon_decoder) {
-  DCHECK(icon_decoder);
+      multidevice_feature_access_manager_(multidevice_feature_access_manager) {
   multidevice_setup_client_->AddObserver(this);
   multidevice_feature_access_manager_->AddObserver(this);
 }
@@ -179,6 +175,7 @@
   }
   pref_service_->SetList(prefs::kRecentAppsHistory,
                          std::move(app_metadata_value_list));
+  has_loaded_prefs_ = true;
 }
 
 void RecentAppsInteractionHandlerImpl::OnFeatureStatesChanged(
@@ -203,54 +200,16 @@
 }
 
 void RecentAppsInteractionHandlerImpl::SetStreamableApps(
-    const proto::StreamableApps& streamable_apps) {
+    const std::vector<Notification::AppMetadata>& streamable_apps) {
   PA_LOG(INFO) << "ClearRecentAppMetadataListAndPref to update the list of "
-               << streamable_apps.apps_size() << " items.";
+               << streamable_apps.size() << " items.";
   ClearRecentAppMetadataListAndPref();
-  std::unique_ptr<std::vector<IconDecoder::DecodingData>> decoding_data_list =
-      std::make_unique<std::vector<IconDecoder::DecodingData>>();
-  std::hash<std::string> str_hash;
-  gfx::Image image =
-      gfx::Image(CreateVectorIcon(kPhoneHubPhoneIcon, gfx::kGoogleGrey700));
-  for (const auto& app : streamable_apps.apps()) {
-    // TODO(nayebi): AppMetadata is no longer limited to Notification class,
-    // let's move it outside of the Notification class.s2
-    recent_app_metadata_list_.emplace_back(
-        Notification::AppMetadata(base::UTF8ToUTF16(app.visible_name()),
-                                  app.package_name(), image, absl::nullopt,
-                                  app.icon_styling() ==
-                                      proto::NotificationIconStyling::
-                                          ICON_STYLE_MONOCHROME_SMALL_ICON,
-                                  app.user_id()),
-        base::Time::FromDoubleT(0));
-    std::string key = app.package_name() + base::NumberToString(app.user_id());
-    decoding_data_list->emplace_back(
-        IconDecoder::DecodingData(str_hash(key), app.icon()));
+
+  // TODO(b/260015890): Save at most 6 apps.
+  for (const auto& app : streamable_apps) {
+    recent_app_metadata_list_.emplace_back(app, base::Time::FromDoubleT(0));
   }
 
-  icon_decoder_->BatchDecode(
-      std::move(decoding_data_list),
-      base::BindOnce(&RecentAppsInteractionHandlerImpl::IconsDecoded,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void RecentAppsInteractionHandlerImpl::IconsDecoded(
-    std::unique_ptr<std::vector<IconDecoder::DecodingData>>
-        decoding_data_list) {
-  std::hash<std::string> str_hash;
-  for (const IconDecoder::DecodingData& decoding_data : *decoding_data_list) {
-    if (decoding_data.result.IsEmpty())
-      continue;
-    // find the associated app metadata
-    for (auto& app_metadata : recent_app_metadata_list_) {
-      std::string key = app_metadata.first.package_name +
-                        base::NumberToString(app_metadata.first.user_id);
-      if (decoding_data.id == str_hash(key)) {
-        app_metadata.first.icon = decoding_data.result;
-        continue;
-      }
-    }
-  }
   SaveRecentAppMetadataListToPref();
   ComputeAndUpdateUiState();
 }
@@ -297,6 +256,7 @@
 void RecentAppsInteractionHandlerImpl::ClearRecentAppMetadataListAndPref() {
   recent_app_metadata_list_.clear();
   pref_service_->ClearPref(prefs::kRecentAppsHistory);
+  has_loaded_prefs_ = false;
 }
 
 }  // namespace phonehub
diff --git a/ash/components/phonehub/recent_apps_interaction_handler_impl.h b/ash/components/phonehub/recent_apps_interaction_handler_impl.h
index 6433ed9..4d86c1f9 100644
--- a/ash/components/phonehub/recent_apps_interaction_handler_impl.h
+++ b/ash/components/phonehub/recent_apps_interaction_handler_impl.h
@@ -8,8 +8,6 @@
 #include <stdint.h>
 #include <memory>
 
-#include "ash/components/phonehub/icon_decoder.h"
-#include "ash/components/phonehub/icon_decoder_impl.h"
 #include "ash/components/phonehub/multidevice_feature_access_manager.h"
 #include "ash/components/phonehub/notification.h"
 #include "ash/components/phonehub/proto/phonehub_api.pb.h"
@@ -38,8 +36,7 @@
   explicit RecentAppsInteractionHandlerImpl(
       PrefService* pref_service,
       multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
-      MultideviceFeatureAccessManager* multidevice_feature_access_manager,
-      IconDecoder* icon_decoder);
+      MultideviceFeatureAccessManager* multidevice_feature_access_manager);
   ~RecentAppsInteractionHandlerImpl() override;
 
   // RecentAppsInteractionHandler:
@@ -64,9 +61,8 @@
   void OnNotificationAccessChanged() override;
   void OnAppsAccessChanged() override;
 
-  void SetStreamableApps(const proto::StreamableApps& streamable_apps) override;
-  void IconsDecoded(std::unique_ptr<std::vector<IconDecoder::DecodingData>>
-                        decoding_data_list);
+  void SetStreamableApps(
+      const std::vector<Notification::AppMetadata>& streamable_apps) override;
 
   std::vector<std::pair<Notification::AppMetadata, base::Time>>*
   recent_app_metadata_list_for_testing() {
@@ -92,7 +88,6 @@
   PrefService* pref_service_;
   multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client_;
   MultideviceFeatureAccessManager* multidevice_feature_access_manager_;
-  IconDecoder* icon_decoder_;
 
   base::WeakPtrFactory<RecentAppsInteractionHandlerImpl> weak_ptr_factory_{
       this};
diff --git a/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc b/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
index ffa9c1d2..c855f1b0 100644
--- a/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
+++ b/ash/components/phonehub/recent_apps_interaction_handler_impl_unittest.cc
@@ -7,8 +7,6 @@
 #include <memory>
 
 #include "ash/components/phonehub/fake_multidevice_feature_access_manager.h"
-#include "ash/components/phonehub/icon_decoder.h"
-#include "ash/components/phonehub/icon_decoder_impl.h"
 #include "ash/components/phonehub/notification.h"
 #include "ash/components/phonehub/pref_names.h"
 #include "ash/constants/ash_features.h"
@@ -52,40 +50,6 @@
 }  // namespace
 
 class RecentAppsInteractionHandlerTest : public testing::Test {
-  class TestDecoderDelegate : public IconDecoderImpl::DecoderDelegate {
-   public:
-    TestDecoderDelegate() = default;
-    ~TestDecoderDelegate() override = default;
-
-    void Decode(const IconDecoder::DecodingData& data,
-                data_decoder::DecodeImageCallback callback) override {
-      pending_callbacks_[data.id] = std::move(callback);
-    }
-
-    void CompleteRequest(const unsigned long id) {
-      SkBitmap test_bitmap;
-      test_bitmap.allocN32Pixels(id % 10, 1);
-      std::move(pending_callbacks_.at(id)).Run(test_bitmap);
-      pending_callbacks_.erase(id);
-    }
-
-    void FailRequest(const unsigned long id) {
-      SkBitmap test_bitmap;
-      std::move(pending_callbacks_.at(id)).Run(test_bitmap);
-      pending_callbacks_.erase(id);
-    }
-
-    void CompleteAllRequests() {
-      for (auto& it : pending_callbacks_)
-        CompleteRequest(it.first);
-      pending_callbacks_.clear();
-    }
-
-   private:
-    base::flat_map<unsigned long, data_decoder::DecodeImageCallback>
-        pending_callbacks_;
-  };
-
  protected:
   RecentAppsInteractionHandlerTest() = default;
   RecentAppsInteractionHandlerTest(const RecentAppsInteractionHandlerTest&) =
@@ -102,14 +66,9 @@
     RecentAppsInteractionHandlerImpl::RegisterPrefs(pref_service_.registry());
     fake_multidevice_setup_client_ =
         std::make_unique<multidevice_setup::FakeMultiDeviceSetupClient>();
-    icon_decoder_ = std::make_unique<IconDecoderImpl>();
-    icon_decoder_.get()->decoder_delegate_ =
-        std::make_unique<TestDecoderDelegate>();
-    decoder_delegate_ = static_cast<TestDecoderDelegate*>(
-        icon_decoder_.get()->decoder_delegate_.get());
     interaction_handler_ = std::make_unique<RecentAppsInteractionHandlerImpl>(
         &pref_service_, fake_multidevice_setup_client_.get(),
-        &fake_multidevice_feature_access_manager_, icon_decoder_.get());
+        &fake_multidevice_feature_access_manager_);
     interaction_handler_->AddRecentAppClickObserver(&fake_click_handler_);
   }
 
@@ -280,8 +239,6 @@
   TestingPrefServiceSimple pref_service_;
   FakeMultideviceFeatureAccessManager fake_multidevice_feature_access_manager_;
   base::test::ScopedFeatureList feature_list_;
-  TestDecoderDelegate* decoder_delegate_;
-  std::unique_ptr<IconDecoderImpl> icon_decoder_;
 };
 
 TEST_F(RecentAppsInteractionHandlerTest, RecentAppsClicked) {
@@ -334,72 +291,70 @@
 }
 
 TEST_F(RecentAppsInteractionHandlerTest, SetStreamableApps) {
-  proto::StreamableApps streamable_apps;
-  auto* app1 = streamable_apps.add_apps();
-  app1->set_visible_name("VisName1");
-  app1->set_package_name("App1");
-  app1->set_icon("icon1");
-
-  auto* app2 = streamable_apps.add_apps();
-  app2->set_visible_name("VisName2");
-  app2->set_package_name("App2");
-  app2->set_icon("icon2");
+  std::vector<Notification::AppMetadata> streamable_apps;
+  streamable_apps.emplace_back(
+      Notification::AppMetadata(u"App1", "com.fakeapp1", gfx::Image(),
+                                /*icon_color=*/absl::nullopt,
+                                /*icon_is_monochrome=*/true, 1));
+  streamable_apps.emplace_back(
+      Notification::AppMetadata(u"App2", "com.fakeapp2", gfx::Image(),
+                                /*icon_color=*/absl::nullopt,
+                                /*icon_is_monochrome=*/true, 1));
 
   handler().SetStreamableApps(streamable_apps);
 
   EXPECT_EQ(2U, handler().recent_app_metadata_list_for_testing()->size());
-  EXPECT_EQ("App1", handler()
-                        .recent_app_metadata_list_for_testing()
-                        ->at(0)
-                        .first.package_name);
-  EXPECT_EQ("App2", handler()
-                        .recent_app_metadata_list_for_testing()
-                        ->at(1)
-                        .first.package_name);
+  EXPECT_EQ("com.fakeapp1", handler()
+                                .recent_app_metadata_list_for_testing()
+                                ->at(0)
+                                .first.package_name);
+  EXPECT_EQ("com.fakeapp2", handler()
+                                .recent_app_metadata_list_for_testing()
+                                ->at(1)
+                                .first.package_name);
 }
 
 TEST_F(RecentAppsInteractionHandlerTest,
        SetStreamableApps_ClearsPreviousState) {
-  proto::StreamableApps streamable_apps;
-  auto* app1 = streamable_apps.add_apps();
-  app1->set_visible_name("VisName1");
-  app1->set_package_name("App1");
-  app1->set_icon("icon1");
-
-  auto* app2 = streamable_apps.add_apps();
-  app2->set_visible_name("VisName2");
-  app2->set_package_name("App2");
-  app2->set_icon("icon2");
+  std::vector<Notification::AppMetadata> streamable_apps;
+  streamable_apps.emplace_back(
+      Notification::AppMetadata(u"App1", "com.fakeapp1", gfx::Image(),
+                                /*icon_color=*/absl::nullopt,
+                                /*icon_is_monochrome=*/true, 1));
+  streamable_apps.emplace_back(
+      Notification::AppMetadata(u"App2", "com.fakeapp2", gfx::Image(),
+                                /*icon_color=*/absl::nullopt,
+                                /*icon_is_monochrome=*/true, 1));
 
   handler().SetStreamableApps(streamable_apps);
 
   EXPECT_EQ(2U, handler().recent_app_metadata_list_for_testing()->size());
-  EXPECT_EQ("App1", handler()
-                        .recent_app_metadata_list_for_testing()
-                        ->at(0)
-                        .first.package_name);
-  EXPECT_EQ("App2", handler()
-                        .recent_app_metadata_list_for_testing()
-                        ->at(1)
-                        .first.package_name);
+  EXPECT_EQ("com.fakeapp1", handler()
+                                .recent_app_metadata_list_for_testing()
+                                ->at(0)
+                                .first.package_name);
+  EXPECT_EQ("com.fakeapp2", handler()
+                                .recent_app_metadata_list_for_testing()
+                                ->at(1)
+                                .first.package_name);
 
-  proto::StreamableApps streamable_apps2;
-  auto* app3 = streamable_apps2.add_apps();
-  app3->set_visible_name("VisName3");
-  app3->set_package_name("App3");
-  app3->set_icon("icon3");
+  std::vector<Notification::AppMetadata> streamable_apps2;
+  streamable_apps2.emplace_back(
+      Notification::AppMetadata(u"App3", "com.fakeapp3", gfx::Image(),
+                                /*icon_color=*/absl::nullopt,
+                                /*icon_is_monochrome=*/true, 1));
 
   handler().SetStreamableApps(streamable_apps2);
 
   EXPECT_EQ(1U, handler().recent_app_metadata_list_for_testing()->size());
-  EXPECT_EQ("App3", handler()
-                        .recent_app_metadata_list_for_testing()
-                        ->at(0)
-                        .first.package_name);
+  EXPECT_EQ("com.fakeapp3", handler()
+                                .recent_app_metadata_list_for_testing()
+                                ->at(0)
+                                .first.package_name);
 }
 
 TEST_F(RecentAppsInteractionHandlerTest, SetStreamableApps_EmptyList) {
-  proto::StreamableApps streamable_apps;
+  std::vector<Notification::AppMetadata> streamable_apps;
 
   handler().SetStreamableApps(streamable_apps);
 
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 082da6c..7c32bc15 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -3636,8 +3636,7 @@
 
 }  // namespace
 
-TEST_F(DisplayManagerTest,
-       InternalDisplayUpdatesDisplayInfoProperlyUponWakeup) {
+TEST_F(DisplayManagerTest, DisconnectedInternalDisplayShouldUpdateDisplayInfo) {
   constexpr int64_t external_id = 123;
   const int64_t internal_id =
       display::test::DisplayManagerTestApi(display_manager())
@@ -3655,18 +3654,18 @@
           .SetNativeMode(MakeDisplayMode())
           .Build();
   EXPECT_FALSE(internal_snapshot->current_mode());
-  outputs.push_back(internal_snapshot.get());
 
+  outputs.push_back(internal_snapshot.get());
   std::unique_ptr<display::DisplaySnapshot> external_snapshot =
       display::FakeDisplaySnapshot::Builder()
           .SetId(external_id)
-          .SetType(display::DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
           .SetNativeMode(MakeDisplayMode())
-          // "Connected display" has the current mode.
-          .SetCurrentMode(MakeDisplayMode())
           .AddMode(MakeDisplayMode())
           .SetOrigin({0, 1000})
           .Build();
+  // "Connectd display" has the current mode.
+  external_snapshot->set_current_mode(external_snapshot->native_mode());
+
   outputs.push_back(external_snapshot.get());
 
   // Update the display manager through DisplayChangeObserver.
@@ -3674,132 +3673,14 @@
   observer.OnDisplayModeChanged(outputs);
 
   EXPECT_EQ(1u, display_manager()->GetNumDisplays());
+  EXPECT_TRUE(display_manager()->IsActiveDisplayId(external_id));
   EXPECT_FALSE(display_manager()->IsActiveDisplayId(internal_id));
-  EXPECT_TRUE(display_manager()->IsActiveDisplayId(external_id));
 
-  {
-    const display::ManagedDisplayInfo& display_info =
-        display_manager()->GetDisplayInfo(internal_id);
-    EXPECT_EQ(1.0f, display_info.device_scale_factor());
-    ASSERT_EQ(1u, display_info.display_modes().size());
-    EXPECT_EQ(1.0f, display_info.display_modes()[0].device_scale_factor());
-  }
-
-  // Turn the internal display on.
-  outputs.front()->set_current_mode(outputs.front()->native_mode());
-  observer.GetStateForDisplayIds(outputs);
-  observer.OnDisplayModeChanged(outputs);
-
-  EXPECT_EQ(2u, display_manager()->GetNumDisplays());
-  EXPECT_TRUE(display_manager()->IsActiveDisplayId(internal_id));
-  EXPECT_TRUE(display_manager()->IsActiveDisplayId(external_id));
-
-  {
-    const display::ManagedDisplayInfo& display_info =
-        display_manager()->GetDisplayInfo(internal_id);
-    EXPECT_EQ(1.6f, display_info.device_scale_factor());
-    ASSERT_EQ(1u, display_info.display_modes().size());
-    EXPECT_EQ(1.6f, display_info.display_modes()[0].device_scale_factor());
-  }
-}
-
-TEST_F(DisplayManagerTest, InternalDisplayUpdatesBoundsUponWakeup) {
-  // DP connector is positioned first in DRM, so external display is detected
-  // first.
-  constexpr int64_t external_id = 123;
-  constexpr int64_t internal_id = 456;
-  display::test::DisplayManagerTestApi(display_manager())
-      .SetInternalDisplayId(internal_id);
-
-  display::Screen* screen = display::Screen::GetScreen();
-  DCHECK(screen);
-  Shell* shell = Shell::Get();
-  display::DisplayChangeObserver observer(shell->display_manager());
-  display::DisplayConfigurator::DisplayStateList outputs;
-  std::unique_ptr<display::DisplaySnapshot> external_snapshot =
-      display::FakeDisplaySnapshot::Builder()
-          .SetId(external_id)
-          .SetType(display::DISPLAY_CONNECTION_TYPE_DISPLAYPORT)
-          .SetNativeMode(MakeDisplayMode())
-          .SetCurrentMode(MakeDisplayMode())
-          .AddMode(MakeDisplayMode())
-          .Build();
-  outputs.push_back(external_snapshot.get());
-
-  std::unique_ptr<display::DisplaySnapshot> internal_snapshot =
-      display::FakeDisplaySnapshot::Builder()
-          .SetId(internal_id)
-          .SetType(display::DISPLAY_CONNECTION_TYPE_INTERNAL)
-          .SetNativeMode(MakeDisplayMode())
-          .SetCurrentMode(MakeDisplayMode())
-          .SetOrigin({0, 1000})
-          .Build();
-  outputs.push_back(internal_snapshot.get());
-
-  // Update the display manager through DisplayChangeObserver.
-  observer.GetStateForDisplayIds(outputs);
-  observer.OnDisplayModeChanged(outputs);
-
-  {
-    // Verify the bounds are set such that the external display is at 0, 0.
-    const display::ManagedDisplayInfo& external_display_info =
-        display_manager()->GetDisplayInfo(external_id);
-    EXPECT_EQ(gfx::Rect(0, 0, 1366, 768),
-              external_display_info.bounds_in_native());
-
-    const display::ManagedDisplayInfo& internal_display_info =
-        display_manager()->GetDisplayInfo(internal_id);
-    EXPECT_EQ(gfx::Rect(0, 1000, 1366, 768),
-              internal_display_info.bounds_in_native());
-  }
-
-  // Turn the displays off.
-  outputs[0]->set_current_mode(nullptr);
-  outputs[1]->set_current_mode(nullptr);
-  observer.GetStateForDisplayIds(outputs);
-  observer.OnDisplayModeChanged(outputs);
-
-  {
-    // Nothing should change.
-    const display::ManagedDisplayInfo& external_display_info =
-        display_manager()->GetDisplayInfo(external_id);
-    EXPECT_EQ(gfx::Rect(0, 0, 1366, 768),
-              external_display_info.bounds_in_native());
-
-    const display::ManagedDisplayInfo& internal_display_info =
-        display_manager()->GetDisplayInfo(internal_id);
-    EXPECT_EQ(gfx::Rect(0, 1000, 1366, 768),
-              internal_display_info.bounds_in_native());
-  }
-
-  // Disconnect the external display.
-  outputs.erase(outputs.begin());
-  outputs[0]->set_origin({0, 0});
-  observer.GetStateForDisplayIds(outputs);
-  observer.OnDisplayModeChanged(outputs);
-
-  {
-    // Verify that the internal display's native bounds have not changed yet,
-    // since we do not configure while it's disabled.
-    const display::ManagedDisplayInfo& internal_display_info =
-        display_manager()->GetDisplayInfo(internal_id);
-    EXPECT_EQ(gfx::Rect(0, 1000, 1366, 768),
-              internal_display_info.bounds_in_native());
-  }
-
-  // Turn the display back on.
-  outputs[0]->set_current_mode(outputs[0]->native_mode());
-  observer.GetStateForDisplayIds(outputs);
-  observer.OnDisplayModeChanged(outputs);
-
-  {
-    // Verify that the internal display updated its origins properly after it
-    // was enabled.
-    const display::ManagedDisplayInfo& internal_display_info =
-        display_manager()->GetDisplayInfo(internal_id);
-    EXPECT_EQ(gfx::Rect(0, 0, 1366, 768),
-              internal_display_info.bounds_in_native());
-  }
+  const display::ManagedDisplayInfo& display_info =
+      display_manager()->GetDisplayInfo(internal_id);
+  EXPECT_EQ(1.6f, display_info.device_scale_factor());
+  ASSERT_EQ(1u, display_info.display_modes().size());
+  EXPECT_EQ(1.6f, display_info.display_modes()[0].device_scale_factor());
 }
 
 // TODO(crbug/1262970): Delete when we can read radius from command line.
diff --git a/ash/system/holding_space/holding_space_tray.cc b/ash/system/holding_space/holding_space_tray.cc
index bd3c746..608709b 100644
--- a/ash/system/holding_space/holding_space_tray.cc
+++ b/ash/system/holding_space/holding_space_tray.cc
@@ -326,7 +326,10 @@
   TooltipTextChanged();
 }
 
-void HoldingSpaceTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {}
+void HoldingSpaceTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {
+  if (bubble_->GetBubbleView() == bubble_view)
+    CloseBubble();
+}
 
 void HoldingSpaceTray::AnchorUpdated() {
   if (bubble_)
@@ -361,10 +364,8 @@
 
   bubble_ = std::make_unique<HoldingSpaceTrayBubble>(this);
 
-  // Observe the bubble widget so that we can do proper clean up when it is
-  // being destroyed. If destruction is due to a call to `CloseBubble()` we will
-  // have already cleaned up state but there are cases where the bubble widget
-  // is destroyed independent of a call to `CloseBubble()`, e.g. ESC key press.
+  // Observe the bubble widget so that we can close the bubble when a holding
+  // space item is being dragged.
   widget_observer_.Observe(bubble_->GetBubbleWidget());
 
   SetIsActive(true);
@@ -674,10 +675,6 @@
                                 weak_factory_.GetWeakPtr()));
 }
 
-void HoldingSpaceTray::OnWidgetDestroying(views::Widget* widget) {
-  CloseBubble();
-}
-
 void HoldingSpaceTray::OnActiveUserPrefServiceChanged(PrefService* prefs) {
   UpdatePreviewsState();
   ObservePrefService(prefs);
diff --git a/ash/system/holding_space/holding_space_tray.h b/ash/system/holding_space/holding_space_tray.h
index 3426a3b5..7158e46c 100644
--- a/ash/system/holding_space/holding_space_tray.h
+++ b/ash/system/holding_space/holding_space_tray.h
@@ -135,7 +135,6 @@
 
   // views::WidgetObserver:
   void OnWidgetDragWillStart(views::Widget* widget) override;
-  void OnWidgetDestroying(views::Widget* widget) override;
 
   // Registers pref change registrars for preferences relevant to the holding
   // space tray state.
diff --git a/ash/system/tray/tray_background_view_unittest.cc b/ash/system/tray/tray_background_view_unittest.cc
index be1678b2..74cffb3a 100644
--- a/ash/system/tray/tray_background_view_unittest.cc
+++ b/ash/system/tray/tray_background_view_unittest.cc
@@ -43,7 +43,11 @@
 
   void HandleLocaleChange() override {}
 
-  void HideBubbleWithView(const TrayBubbleView* bubble_view) override {}
+  void HideBubbleWithView(const TrayBubbleView* bubble_view) override {
+    if (bubble_view == bubble_->GetBubbleView())
+      CloseBubble();
+  }
+
   std::unique_ptr<ui::SimpleMenuModel> CreateContextMenuModel() override {
     return provide_menu_model_ ? std::make_unique<ui::SimpleMenuModel>(this)
                                : nullptr;
@@ -55,7 +59,31 @@
     on_bubble_visibility_change_captured_visibility_ = visible;
   }
 
-  void ShowBubble() override { show_bubble_called_ = true; }
+  void ShowBubble() override {
+    show_bubble_called_ = true;
+
+    TrayBubbleView::InitParams init_params;
+    init_params.delegate = GetWeakPtr();
+    init_params.parent_window =
+        Shell::GetContainer(Shell::GetPrimaryRootWindow(),
+                            kShellWindowId_AccessibilityBubbleContainer);
+    init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect;
+    init_params.preferred_width = 200;
+    auto bubble_view = std::make_unique<TrayBubbleView>(init_params);
+    bubble_view->SetCanActivate(true);
+    bubble_ = std::make_unique<TrayBubbleWrapper>(this,
+                                                  /*event_handling=*/false);
+    bubble_->ShowBubble(std::move(bubble_view));
+    bubble_->GetBubbleWidget()->Activate();
+    bubble_->bubble_view()->SetVisible(true);
+
+    SetIsActive(true);
+  }
+
+  void CloseBubble() override {
+    bubble_.reset();
+    SetIsActive(false);
+  }
 
   // ui::SimpleMenuModel::Delegate:
   void ExecuteCommand(int command_id, int event_flags) override {}
@@ -68,12 +96,15 @@
     SetContextMenuEnabled(should_show_menu);
   }
 
+  TrayBubbleWrapper* bubble() { return bubble_.get(); }
+
   bool show_bubble_called() const { return show_bubble_called_; }
 
   views::Widget* on_bubble_visibility_change_captured_widget_ = nullptr;
   bool on_bubble_visibility_change_captured_visibility_ = false;
 
  private:
+  std::unique_ptr<TrayBubbleWrapper> bubble_;
   bool provide_menu_model_ = false;
   bool show_bubble_called_ = false;
 };
@@ -403,23 +434,9 @@
 
   test_tray_background_view()->SetVisiblePreferred(true);
 
-  TrayBubbleView::InitParams init_params;
-  init_params.delegate = test_tray_background_view()->GetWeakPtr();
-  init_params.parent_window =
-      Shell::GetContainer(Shell::GetPrimaryRootWindow(),
-                          kShellWindowId_AccessibilityBubbleContainer);
-  init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect;
-  init_params.preferred_width = 200;
-  auto bubble_view = std::make_unique<TrayBubbleView>(init_params);
-  bubble_view->SetCanActivate(true);
-  auto bubble_ =
-      std::make_unique<TrayBubbleWrapper>(test_tray_background_view(),
-                                          /*event_handling=*/false);
-  bubble_->ShowBubble(std::move(bubble_view));
-  bubble_->GetBubbleWidget()->Activate();
-  bubble_->bubble_view()->SetVisible(true);
+  test_tray_background_view()->ShowBubble();
 
-  EXPECT_EQ(bubble_->GetBubbleWidget(),
+  EXPECT_EQ(test_tray_background_view()->bubble()->GetBubbleWidget(),
             test_tray_background_view()
                 ->on_bubble_visibility_change_captured_widget_);
   EXPECT_TRUE(test_tray_background_view()
@@ -500,4 +517,24 @@
       /*count=*/1);
 }
 
+// Tests that the `TrayBubbleWrapper` owned by the `TrayBackgroundView` is
+// cleaned up and the active state of the `TrayBackgroundView` is updated if the
+// bubble widget is destroyed independently (Real life examples would be
+// clicking outside a bubble or hitting the escape key).
+TEST_F(TrayBackgroundViewTest, CleanUpOnIndependentBubbleDestruction) {
+  test_tray_background_view()->SetVisiblePreferred(true);
+  test_tray_background_view()->ShowBubble();
+
+  EXPECT_TRUE(test_tray_background_view()->is_active());
+  EXPECT_TRUE(
+      test_tray_background_view()->bubble()->GetBubbleWidget()->IsVisible());
+
+  // Destroying the bubble's widget independently of the `TrayBackgroundView`
+  // should properly clean up `bubble()` in `TrayBackgroundView`.
+  test_tray_background_view()->bubble()->GetBubbleWidget()->CloseNow();
+
+  EXPECT_FALSE(test_tray_background_view()->is_active());
+  ASSERT_FALSE(test_tray_background_view()->bubble());
+}
+
 }  // namespace ash
diff --git a/ash/webui/common/resources/keyboard_key.html b/ash/webui/common/resources/keyboard_key.html
index 49bd7bc..c5490d07 100644
--- a/ash/webui/common/resources/keyboard_key.html
+++ b/ash/webui/common/resources/keyboard_key.html
@@ -1,4 +1,44 @@
 <style include="cr-shared-style">
+    @media (min-width: 600px) {
+      :host {
+        --keyboard-key-icon-size: 10px;
+      }
+      #key {
+        font-size: 10px;
+        line-height: 10px;
+      }
+    }
+
+    @media (min-width: 768px) {
+      :host {
+        --keyboard-key-icon-size: 12px;
+      }
+      #key {
+        font-size: 11px;
+        line-height: 16px;
+      }
+    }
+
+    @media (min-width: 960px) {
+      :host {
+        --keyboard-key-icon-size: 14px;
+      }
+      #key {
+        font-size: 12px;
+        line-height: 18px;
+      }
+    }
+
+    @media (min-width: 1280px) {
+      :host {
+        --keyboard-key-icon-size: 20px;
+      }
+      #key {
+        font-size: 13px;
+        line-height: 20px;
+      }
+    }
+
   :host {
     --background-color-pressed: var(--cros-icon-color-selection);
     --background-color-unpressed: var(--cros-highlight-color);
@@ -25,7 +65,7 @@
     bottom: var(--travel);
     color: var(--foreground-color-unpressed);
     display: grid;
-    font-size: calc(max(1.25vw, 13px));
+    font-family: 'Google Sans', sans-serif;
     grid-auto-columns: 1fr;
     grid-auto-flow: column;
     grid-template-columns: 1fr;
diff --git a/ash/webui/diagnostics_ui/diagnostics_ui.cc b/ash/webui/diagnostics_ui/diagnostics_ui.cc
index f819a66e..7e1975ec 100644
--- a/ash/webui/diagnostics_ui/diagnostics_ui.cc
+++ b/ash/webui/diagnostics_ui/diagnostics_ui.cc
@@ -208,7 +208,6 @@
       {"inputDeviceTest", IDS_INPUT_DIAGNOSTICS_RUN_TEST},
       {"inputDeviceUntestableNote", IDS_INPUT_DIAGNOSTICS_UNTESTABLE_NOTE},
       {"inputTesterDone", IDS_INPUT_DIAGNOSTICS_TESTER_DONE},
-      {"inputText", IDS_DIAGNOSTICS_INPUT},
       {"internetConnectivityGroupLabel",
        IDS_DIAGNOSTICS_INTERNET_CONNECTIVITY_GROUP_LABEL},
       {"ipConfigInfoDrawerGateway",
@@ -222,6 +221,7 @@
       {"keyboardTesterInstruction",
        IDS_INPUT_DIAGNOSTICS_KEYBOARD_TESTER_INSTRUCTION},
       {"keyboardTesterTitle", IDS_INPUT_DIAGNOSTICS_KEYBOARD_TESTER_TITLE},
+      {"keyboardText", IDS_DIAGNOSTICS_KEYBOARD},
       {"joinNetworkLinkText", IDS_DIAGNOSTICS_JOIN_NETWORK_LINK_TEXT},
       {"lanConnectivityFailedText",
        IDS_DIAGNOSTICS_LAN_CONNECTIVITY_FAILED_TEXT},
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_app.html b/ash/webui/diagnostics_ui/resources/diagnostics_app.html
index 753b863..1b39895 100644
--- a/ash/webui/diagnostics_ui/resources/diagnostics_app.html
+++ b/ash/webui/diagnostics_ui/resources/diagnostics_app.html
@@ -36,6 +36,11 @@
    bottom: 0;
    left: 0;
   }
+
+  cr-toast iron-icon {
+    --iron-icon-fill-color: var(--cros-text-color-prominent);
+    margin-inline-end: 12px;
+  }
 </style>
 <div id="diagnosticsAppContainer">
   <navigation-view-panel id="navigationPanel" show-tool-bar
@@ -60,6 +65,7 @@
     </div>
   </navigation-view-panel>
   <cr-toast id="toast" duration="2500">
+    <iron-icon icon="diagnostics:info"></iron-icon>
     <span>[[toastText_]]</span>
   </cr-toast>
 </div>
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_app.ts b/ash/webui/diagnostics_ui/resources/diagnostics_app.ts
index 4896da7..c5734c5 100644
--- a/ash/webui/diagnostics_ui/resources/diagnostics_app.ts
+++ b/ash/webui/diagnostics_ui/resources/diagnostics_app.ts
@@ -5,6 +5,7 @@
 import 'chrome://resources/ash/common/navigation_view_panel.js';
 import 'chrome://resources/ash/common/page_toolbar.js';
 import 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import './diagnostics_sticky_banner.js';
 import './diagnostics_shared.css.js';
 import './input_list.js';
@@ -239,7 +240,7 @@
   // the input page to the navigation panel.
   private createInputSelector(): SelectorItem {
     return this.$.navigationPanel.createSelectorItem(
-        loadTimeData.getString('inputText'), 'input-list',
+        loadTimeData.getString('keyboardText'), 'input-list',
         getDiagnosticsIcon('keyboard'), 'input');
   }
 }
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_shared.css b/ash/webui/diagnostics_ui/resources/diagnostics_shared.css
index a300baa..39f86dc 100644
--- a/ash/webui/diagnostics_ui/resources/diagnostics_shared.css
+++ b/ash/webui/diagnostics_ui/resources/diagnostics_shared.css
@@ -5,6 +5,7 @@
 /* #css_wrapper_metadata_start
  * #type=style
  * #import=chrome://resources/ash/common/navigation_shared_vars.css.js
+ * #import=chrome://resources/cr_elements/chromeos/cros_color_overrides.css.js
  * #import=chrome://resources/cr_elements/cr_shared_style.css.js
  * #import=chrome://resources/cr_elements/cr_shared_vars.css.js
  * #include=cr-shared-style
diff --git a/ash/webui/diagnostics_ui/resources/index.html b/ash/webui/diagnostics_ui/resources/index.html
index a3ae7a4..68692809 100644
--- a/ash/webui/diagnostics_ui/resources/index.html
+++ b/ash/webui/diagnostics_ui/resources/index.html
@@ -6,10 +6,10 @@
   <head>
     <meta charset="utf-8">
     <title></title>
+    <link rel="stylesheet" href="chrome://resources/chromeos/colors/cros_styles.css">
+    <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
+    <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
   </head>
-  <link rel="stylesheet" href="chrome://resources/chromeos/colors/cros_styles.css">
-  <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
-  <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
   <style>
     /* The :not(body) selector allows the variable definitions below to 'win'
        against the shared ones. */
diff --git a/ash/webui/diagnostics_ui/resources/input_card.html b/ash/webui/diagnostics_ui/resources/input_card.html
index 816f855..5f4948f 100644
--- a/ash/webui/diagnostics_ui/resources/input_card.html
+++ b/ash/webui/diagnostics_ui/resources/input_card.html
@@ -1,6 +1,5 @@
 <style include="diagnostics-shared">
   .device {
-    border-bottom: 1px solid var(--cros-separator-color);
     display: flex;
     padding: 12px 20px;
   }
diff --git a/ash/webui/diagnostics_ui/resources/keyboard_tester.html b/ash/webui/diagnostics_ui/resources/keyboard_tester.html
index 6b8b36d..e0a8e216 100644
--- a/ash/webui/diagnostics_ui/resources/keyboard_tester.html
+++ b/ash/webui/diagnostics_ui/resources/keyboard_tester.html
@@ -1,6 +1,26 @@
 <style>
-  #dialog {
-    --cr-dialog-width: calc(100% - 80px);
+  @media (min-width: 600px) {
+    :host {
+      --cr-dialog-width: 416px;
+    }
+  }
+
+  @media (min-width: 768px) {
+    :host {
+      --cr-dialog-width: 512px;
+    }
+  }
+
+  @media (min-width: 960px) {
+    :host {
+      --cr-dialog-width: 672px;
+    }
+  }
+
+  @media (min-width: 1280px) {
+    :host {
+      --cr-dialog-width: 960px;
+    }
   }
 
   [slot='title'] {
@@ -23,15 +43,20 @@
     text-decoration: none;
   }
 
+  #lostFocusToast {
+    bottom: 0;
+    left: 0;
+  }
+
   cr-toast iron-icon {
-    --iron-icon-fill-color: var(--cros-toast-icon-color);
+    --iron-icon-fill-color: var(--cros-text-color-prominent);
     margin-inline-end: 12px;
   }
 </style>
 <cr-dialog id="dialog" on-close="handleClose">
-  <div slot="title">[[i18n('keyboardTesterTitle')]]</div>
+  <div slot="title" aria-labelledby="description">[[i18n('keyboardTesterTitle')]]</div>
   <div slot="body">
-    <p>[[i18n('keyboardTesterInstruction')]]</p>
+    <p id="description">[[i18n('keyboardTesterInstruction')]]</p>
     <template is="dom-if" if="[[layoutIsKnown_]]">
       <div id="diagram-border">
         <keyboard-diagram
@@ -46,8 +71,8 @@
         </keyboard-diagram>
       </div>
     </template>
-    <cr-toast id="lostFocusToast">
-      <iron-icon icon="diagnostics:window"></iron-icon>
+    <cr-toast id="lostFocusToast" duration="[[lostFocusToastLingerMs]]">
+      <iron-icon icon="diagnostics:keyboard"></iron-icon>
       <!--
         Though the message refers to "other windows", it also applies when
         the user opens the launcher, but not if they just click another element
diff --git a/ash/webui/diagnostics_ui/resources/keyboard_tester.ts b/ash/webui/diagnostics_ui/resources/keyboard_tester.ts
index 5efa8636..f154989a 100644
--- a/ash/webui/diagnostics_ui/resources/keyboard_tester.ts
+++ b/ash/webui/diagnostics_ui/resources/keyboard_tester.ts
@@ -117,6 +117,9 @@
   111,  // KEY_DELETE
 ]);
 
+const DISPLAY_TOAST_INDEFINITELY_MS = 0;
+const TOAST_LINGER_MS = 1000;
+
 const KeyboardTesterElementBase = I18nMixin(PolymerElement);
 
 export class KeyboardTesterElement extends KeyboardTesterElementBase {
@@ -170,6 +173,12 @@
         type: Boolean,
         value: loadTimeData.getBoolean('isLoggedIn'),
       },
+
+      lostFocusToastLingerMs: {
+        type: Number,
+        value: DISPLAY_TOAST_INDEFINITELY_MS,
+      },
+
     };
   }
 
@@ -178,6 +187,7 @@
   // string.
   protected isLoggedIn: boolean;
   protected diagramTopRightKey_: string;
+  private lostFocusToastLingerMs: number;
   private layoutIsKnown_: boolean;
   // TODO(crbug.com/1257138): use the proper type annotation instead of
   // string.
@@ -295,7 +305,11 @@
     this.inputDataProvider.observeKeyEvents(
         this.keyboard.id, this.receiver_.$.bindNewPipeAndPassRemote());
     this.addEventListeners();
+    const title: HTMLElement|null =
+        this.shadowRoot!.querySelector('div[slot="title"]');
+    this.$.dialog.getNative().removeAttribute('aria-describedby');
     this.$.dialog.showModal();
+    title?.focus();
   }
 
   // Prevent the default behavior for keydown/keyup only when the keyboard
@@ -398,6 +412,7 @@
         this.shadowRoot!.querySelector('#diagram');
     assert(diagram);
     diagram.clearPressedKeys();
+    this.lostFocusToastLingerMs = DISPLAY_TOAST_INDEFINITELY_MS;
     this.$.lostFocusToast.show();
   }
 
@@ -408,7 +423,9 @@
     if (this.isOpen()) {
       this.$.dialog.focus();
     }
-    this.$.lostFocusToast.hide();
+
+    // Show focus lost toast for 1 second after regaining focus.
+    this.lostFocusToastLingerMs = TOAST_LINGER_MS;
   }
 }
 
diff --git a/ash/wm/desks/templates/restore_data_collector.cc b/ash/wm/desks/templates/restore_data_collector.cc
index 84a1aa8..38f06ca 100644
--- a/ash/wm/desks/templates/restore_data_collector.cc
+++ b/ash/wm/desks/templates/restore_data_collector.cc
@@ -166,8 +166,11 @@
       root_window_to_show = Shell::Get()->GetPrimaryRootWindow();
 
     // There were some unsupported apps in the active desk so open up a dialog
-    // to let the user know.
-    saved_desk_util::GetSavedDeskDialogController()->ShowUnsupportedAppsDialog(
+    // to let the user know. The dialog controller should always be available
+    // here since we have already determined that we are in overview mode.
+    auto* dialog_controller = saved_desk_util::GetSavedDeskDialogController();
+    DCHECK(dialog_controller);
+    dialog_controller->ShowUnsupportedAppsDialog(
         root_window_to_show, call.unsupported_apps, call.incognito_window_count,
         std::move(call.callback), std::move(desk_template));
   } else {
diff --git a/ash/wm/desks/templates/saved_desk_item_view.cc b/ash/wm/desks/templates/saved_desk_item_view.cc
index 87edbd8..bfb52f29 100644
--- a/ash/wm/desks/templates/saved_desk_item_view.cc
+++ b/ash/wm/desks/templates/saved_desk_item_view.cc
@@ -343,8 +343,12 @@
                                                const base::GUID& uuid) {
   // Show replace template dialog. If accepted, replace old template and commit
   // name change.
+  auto* controller = saved_desk_util::GetSavedDeskDialogController();
+  if (!controller)
+    return;
+
   aura::Window* root_window = GetWidget()->GetNativeWindow()->GetRootWindow();
-  saved_desk_util::GetSavedDeskDialogController()->ShowReplaceDialog(
+  controller->ShowReplaceDialog(
       root_window, name_view_->GetText(), type,
       base::BindOnce(&SavedDeskItemView::ReplaceTemplate,
                      weak_ptr_factory_.GetWeakPtr(), uuid),
@@ -716,7 +720,11 @@
 
 void SavedDeskItemView::OnDeleteButtonPressed() {
   // Show the dialog to confirm the deletion.
-  saved_desk_util::GetSavedDeskDialogController()->ShowDeleteDialog(
+  auto* controller = saved_desk_util::GetSavedDeskDialogController();
+  if (!controller)
+    return;
+
+  controller->ShowDeleteDialog(
       GetWidget()->GetNativeWindow()->GetRootWindow(),
       name_view_->GetAccessibleName(), desk_template_->type(),
       base::BindOnce(&SavedDeskItemView::OnDeleteTemplate,
diff --git a/ash/wm/desks/templates/saved_desk_unittest.cc b/ash/wm/desks/templates/saved_desk_unittest.cc
index 8f7dc5d..b511110 100644
--- a/ash/wm/desks/templates/saved_desk_unittest.cc
+++ b/ash/wm/desks/templates/saved_desk_unittest.cc
@@ -3193,6 +3193,42 @@
   histogram_tester.ExpectBucketCount(kUserTemplateCountHistogramName, 3, 1);
 }
 
+// Test that things don't crash when exiting overview immediately after
+// triggering the replace dialog. Regression test for http://b/258306298.
+TEST_F(SavedDeskTest, ReplaceTemplateAndExitOverview) {
+  UpdateDisplay("800x600");
+
+  AddEntry(base::GUID::GenerateRandomV4(), "template_1", base::Time::Now(),
+           DeskTemplateType::kTemplate);
+  AddEntry(base::GUID::GenerateRandomV4(), "template_2", base::Time::Now(),
+           DeskTemplateType::kTemplate);
+
+  OpenOverviewAndShowTemplatesGrid();
+
+  SavedDeskNameView* name_view = GetItemViewFromTemplatesGrid(1)->name_view();
+  // Ensure that we have the right item.
+  EXPECT_EQ(name_view->GetText(), u"template_2");
+
+  ClickOnView(name_view);
+  EXPECT_TRUE(name_view->HasFocus());
+
+  // Change the name of "template_2" to "template_1", which will trigger the
+  // replace dialog to be shown.
+  SendKey(ui::VKEY_RIGHT);
+  SendKey(ui::VKEY_BACK);
+  SendKey(ui::VKEY_1);
+  SendKey(ui::VKEY_RETURN);
+
+  // Immediately exit overview. It is important that this is done with a
+  // non-zero duration. This will cause saved desk UI items to live on for
+  // slightly longer as they will be briefly owned by an animation.
+  ui::ScopedAnimationDurationScaleMode animation(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
+  ToggleOverview();
+  WaitForOverviewExitAnimation();
+}
+
 // Tests record metrics when current template being replaced.
 TEST_F(SavedDeskTest, ReplaceTemplateMetric) {
   base::HistogramTester histogram_tester;
diff --git a/ash/wm/desks/templates/saved_desk_util.cc b/ash/wm/desks/templates/saved_desk_util.cc
index fc249d6..7132fa45 100644
--- a/ash/wm/desks/templates/saved_desk_util.cc
+++ b/ash/wm/desks/templates/saved_desk_util.cc
@@ -68,13 +68,14 @@
 }
 
 SavedDeskDialogController* GetSavedDeskDialogController() {
-  auto* overview_session =
-      Shell::Get()->overview_controller()->overview_session();
-  DCHECK(overview_session);
-  SavedDeskDialogController* controller =
-      overview_session->saved_desk_dialog_controller();
-  DCHECK(controller);
-  return controller;
+  auto* overview_controller = Shell::Get()->overview_controller();
+  if (!overview_controller->InOverviewSession())
+    return nullptr;
+
+  SavedDeskDialogController* dialog_controller =
+      overview_controller->overview_session()->saved_desk_dialog_controller();
+  DCHECK(dialog_controller);
+  return dialog_controller;
 }
 
 SavedDeskPresenter* GetSavedDeskPresenter() {
diff --git a/ash/wm/desks/templates/saved_desk_util.h b/ash/wm/desks/templates/saved_desk_util.h
index 409ccf8..64d4077 100644
--- a/ash/wm/desks/templates/saved_desk_util.h
+++ b/ash/wm/desks/templates/saved_desk_util.h
@@ -26,8 +26,10 @@
 
 ASH_EXPORT bool IsSavedDesksEnabled();
 
+// Will return null if overview mode is not active.
 ASH_EXPORT SavedDeskDialogController* GetSavedDeskDialogController();
 
+// Will DCHECK if overview mode is not active.
 ASH_EXPORT SavedDeskPresenter* GetSavedDeskPresenter();
 
 }  // namespace saved_desk_util
diff --git a/base/message_loop/message_pump_kqueue.cc b/base/message_loop/message_pump_kqueue.cc
index 6a8f134..400c1ba 100644
--- a/base/message_loop/message_pump_kqueue.cc
+++ b/base/message_loop/message_pump_kqueue.cc
@@ -7,6 +7,7 @@
 #include <sys/errno.h>
 
 #include "base/auto_reset.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/mac/mac_util.h"
 #include "base/mac/mach_logging.h"
@@ -18,6 +19,13 @@
 
 namespace {
 
+// Under this feature a simplified version of the Run() function is used. It
+// improves legibility and avoids some calls to kevent64(). Remove once
+// crbug.com/1200141 is resolved.
+BASE_FEATURE(kUseSimplifiedMessagePumpKqueueLoop,
+             "UseSimplifiedMessagePumpKqueueLoop",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 #if DCHECK_IS_ON()
 // Prior to macOS 10.14, kqueue timers may spuriously wake up, because earlier
 // wake ups race with timer resets in the kernel. As of macOS 10.14, updating a
@@ -139,28 +147,55 @@
 void MessagePumpKqueue::Run(Delegate* delegate) {
   AutoReset<bool> reset_keep_running(&keep_running_, true);
 
+  if (base::FeatureList::IsEnabled(kUseSimplifiedMessagePumpKqueueLoop)) {
+    RunSimplified(delegate);
+  } else {
+    while (keep_running_) {
+      mac::ScopedNSAutoreleasePool pool;
+
+      bool do_more_work = DoInternalWork(delegate, nullptr);
+      if (!keep_running_)
+        break;
+
+      Delegate::NextWorkInfo next_work_info = delegate->DoWork();
+      do_more_work |= next_work_info.is_immediate();
+      if (!keep_running_)
+        break;
+
+      if (do_more_work)
+        continue;
+
+      do_more_work |= delegate->DoIdleWork();
+      if (!keep_running_)
+        break;
+
+      if (do_more_work)
+        continue;
+
+      DoInternalWork(delegate, &next_work_info);
+    }
+  }
+}
+
+void MessagePumpKqueue::RunSimplified(Delegate* delegate) {
+  // Look for native work once before the loop starts. Without this call the
+  // loop would break without checking native work even once in cases where
+  // QuitWhenIdle was used. This is sometimes the case in tests.
+  DoInternalWork(delegate, nullptr);
+
   while (keep_running_) {
     mac::ScopedNSAutoreleasePool pool;
 
-    bool do_more_work = DoInternalWork(delegate, nullptr);
-    if (!keep_running_)
-      break;
-
     Delegate::NextWorkInfo next_work_info = delegate->DoWork();
-    do_more_work |= next_work_info.is_immediate();
     if (!keep_running_)
       break;
 
-    if (do_more_work)
-      continue;
-
-    do_more_work |= delegate->DoIdleWork();
+    if (!next_work_info.is_immediate()) {
+      delegate->DoIdleWork();
+    }
     if (!keep_running_)
       break;
 
-    if (do_more_work)
-      continue;
-
     DoInternalWork(delegate, &next_work_info);
   }
 }
diff --git a/base/message_loop/message_pump_kqueue.h b/base/message_loop/message_pump_kqueue.h
index cc05442..2e55e4f 100644
--- a/base/message_loop/message_pump_kqueue.h
+++ b/base/message_loop/message_pump_kqueue.h
@@ -107,6 +107,8 @@
 
   // MessagePump:
   void Run(Delegate* delegate) override;
+  // Simplified version of the loop used under experiment (crbug.com/1200141)
+  void RunSimplified(Delegate* delegate);
   void Quit() override;
   void ScheduleWork() override;
   void ScheduleDelayedWork(
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 475cfdd..734ee11 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -135,16 +135,21 @@
   return (c >= 'a' && c <= 'z') ? static_cast<CharT>(c + 'A' - 'a') : c;
 }
 
-// Converts the given string to it's ASCII-lowercase equivalent.
+// Converts the given string to its ASCII-lowercase equivalent. Non-ASCII
+// bytes (or UTF-16 code units in `StringPiece16`) are permitted but will be
+// unmodified.
 BASE_EXPORT std::string ToLowerASCII(StringPiece str);
 BASE_EXPORT std::u16string ToLowerASCII(StringPiece16 str);
 
-// Converts the given string to it's ASCII-uppercase equivalent.
+// Converts the given string to its ASCII-uppercase equivalent. Non-ASCII
+// bytes (or UTF-16 code units in `StringPiece16`) are permitted but will be
+// unmodified.
 BASE_EXPORT std::string ToUpperASCII(StringPiece str);
 BASE_EXPORT std::u16string ToUpperASCII(StringPiece16 str);
 
-// Functor for case-insensitive ASCII comparisons for STL algorithms like
-// std::search.
+// Functor for ASCII case-insensitive comparisons for STL algorithms like
+// std::search. Non-ASCII bytes (or UTF-16 code units in `StringPiece16`) are
+// permitted but will be compared as-is.
 //
 // Note that a full Unicode version of this functor is not possible to write
 // because case mappings might change the number of characters, depend on
@@ -158,13 +163,17 @@
   }
 };
 
-// Like strcasecmp for case-insensitive ASCII characters only. Returns:
+// Like strcasecmp for ASCII case-insensitive comparisons only. Returns:
 //   -1  (a < b)
 //    0  (a == b)
 //    1  (a > b)
-// (unlike strcasecmp which can return values greater or less than 1/-1). For
-// full Unicode support, use base::i18n::ToLower or base::i18n::FoldCase
-// and then just call the normal string operators on the result.
+// (unlike strcasecmp which can return values greater or less than 1/-1). To
+// compare all Unicode code points case-insensitively, use base::i18n::ToLower
+// or base::i18n::FoldCase and then just call the normal string operators on the
+// result.
+//
+// Non-ASCII bytes (or UTF-16 code units in `StringPiece16`) are permitted but
+// will be compared unmodified.
 BASE_EXPORT constexpr int CompareCaseInsensitiveASCII(StringPiece a,
                                                       StringPiece b) {
   return internal::CompareCaseInsensitiveASCIIT(a, b);
@@ -174,9 +183,11 @@
   return internal::CompareCaseInsensitiveASCIIT(a, b);
 }
 
-// Equality for ASCII case-insensitive comparisons. For full Unicode support,
-// use base::i18n::ToLower or base::i18n::FoldCase and then compare with either
-// == or !=.
+// Equality for ASCII case-insensitive comparisons. Non-ASCII bytes (or UTF-16
+// code units in `StringPiece16`) are permitted but will be compared unmodified.
+// To compare all Unicode code points case-insensitively, use
+// base::i18n::ToLower or base::i18n::FoldCase and then compare with either ==
+// or !=.
 inline bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
   return internal::EqualsCaseInsensitiveASCIIT(a, b);
 }
diff --git a/base/strings/string_util_internal.h b/base/strings/string_util_internal.h
index e8702bb..978088f 100644
--- a/base/strings/string_util_internal.h
+++ b/base/strings/string_util_internal.h
@@ -5,6 +5,8 @@
 #ifndef BASE_STRINGS_STRING_UTIL_INTERNAL_H_
 #define BASE_STRINGS_STRING_UTIL_INTERNAL_H_
 
+#include <type_traits>
+
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_piece.h"
 
@@ -18,15 +20,18 @@
   return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
 }
 
-template <typename T, typename CharT = typename T::value_type>
+template <typename T>
 constexpr int CompareCaseInsensitiveASCIIT(T a, T b) {
   // Find the first characters that aren't equal and compare them.  If the end
   // of one of the strings is found before a nonequal character, the lengths
-  // of the strings are compared.
+  // of the strings are compared. Compare using the unsigned type so the sort
+  // order is independent of the signedness of `char`.
+  static_assert(std::is_integral_v<typename T::value_type>);
+  using UCharT = std::make_unsigned_t<typename T::value_type>;
   size_t i = 0;
   while (i < a.length() && i < b.length()) {
-    CharT lower_a = ToLowerASCII(a[i]);
-    CharT lower_b = ToLowerASCII(b[i]);
+    UCharT lower_a = static_cast<UCharT>(ToLowerASCII(a[i]));
+    UCharT lower_b = static_cast<UCharT>(ToLowerASCII(b[i]));
     if (lower_a < lower_b)
       return -1;
     if (lower_a > lower_b)
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index 9d522b0..d5a351d 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -648,6 +648,11 @@
 
   EXPECT_EQ("cc2", ToLowerASCII("Cc2"));
   EXPECT_EQ(u"cc2", ToLowerASCII(u"Cc2"));
+
+  // Non-ASCII characters are unmodified. U+00C4 is LATIN CAPITAL LETTER A WITH
+  // DIAERESIS.
+  EXPECT_EQ('\xc4', ToLowerASCII('\xc4'));
+  EXPECT_EQ(u'\x00c4', ToLowerASCII(u'\x00c4'));
 }
 
 TEST(StringUtilTest, ToUpperASCII) {
@@ -661,6 +666,11 @@
 
   EXPECT_EQ("CC2", ToUpperASCII("Cc2"));
   EXPECT_EQ(u"CC2", ToUpperASCII(u"Cc2"));
+
+  // Non-ASCII characters are unmodified. U+00E4 is LATIN SMALL LETTER A WITH
+  // DIAERESIS.
+  EXPECT_EQ('\xe4', ToUpperASCII('\xe4'));
+  EXPECT_EQ(u'\x00e4', ToUpperASCII(u'\x00e4'));
 }
 
 TEST(StringUtilTest, FormatBytesUnlocalized) {
@@ -1475,6 +1485,15 @@
   EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AsdfA", "aSDfb"));
   EXPECT_EQ(1, CompareCaseInsensitiveASCII("Asdfb", "aSDfA"));
 
+  // Non-ASCII bytes are permitted, but they will be compared case-sensitively.
+  EXPECT_EQ(0, CompareCaseInsensitiveASCII("aaa \xc3\xa4", "AAA \xc3\xa4"));
+  EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AAA \xc3\x84", "aaa \xc3\xa4"));
+  EXPECT_EQ(1, CompareCaseInsensitiveASCII("aaa \xc3\xa4", "AAA \xc3\x84"));
+
+  // ASCII bytes should sort before non-ASCII ones.
+  EXPECT_EQ(-1, CompareCaseInsensitiveASCII("a", "\xc3\xa4"));
+  EXPECT_EQ(1, CompareCaseInsensitiveASCII("\xc3\xa4", "a"));
+
   // For constexpr.
   static_assert(CompareCaseInsensitiveASCII("", "") == 0);
   static_assert(CompareCaseInsensitiveASCII("Asdf", "aSDf") == 0);
@@ -1482,6 +1501,14 @@
   static_assert(CompareCaseInsensitiveASCII("AsdfA", "aSDf") == 1);
   static_assert(CompareCaseInsensitiveASCII("AsdfA", "aSDfb") == -1);
   static_assert(CompareCaseInsensitiveASCII("Asdfb", "aSDfA") == 1);
+  static_assert(CompareCaseInsensitiveASCII("aaa \xc3\xa4", "AAA \xc3\xa4") ==
+                0);
+  static_assert(CompareCaseInsensitiveASCII("AAA \xc3\x84", "aaa \xc3\xa4") ==
+                -1);
+  static_assert(CompareCaseInsensitiveASCII("aaa \xc3\xa4", "AAA \xc3\x84") ==
+                1);
+  static_assert(CompareCaseInsensitiveASCII("a", "\xc3\xa4") == -1);
+  static_assert(CompareCaseInsensitiveASCII("\xc3\xa4", "a") == 1);
 }
 
 TEST(StringUtilTest, EqualsCaseInsensitiveASCII) {
@@ -1505,6 +1532,10 @@
   EXPECT_FALSE(EqualsCaseInsensitiveASCII("bsdf", u"aSDF"));
   EXPECT_FALSE(EqualsCaseInsensitiveASCII("Asdf", u"aSDFz"));
 
+  // Non-ASCII bytes are permitted, but they will be compared case-sensitively.
+  EXPECT_TRUE(EqualsCaseInsensitiveASCII("aaa \xc3\xa4", "AAA \xc3\xa4"));
+  EXPECT_FALSE(EqualsCaseInsensitiveASCII("aaa \xc3\x84", "AAA \xc3\xa4"));
+
   // The `WStringPiece` overloads are only defined on Windows.
 #if BUILDFLAG(IS_WIN)
   EXPECT_TRUE(EqualsCaseInsensitiveASCII(L"", L""));
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java
index 682aa74..32d1cef 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java
@@ -21,6 +21,8 @@
 import com.google.android.apps.common.testing.accessibility.framework.ClickableSpanViewCheck;
 import com.google.android.apps.common.testing.accessibility.framework.DuplicateClickableBoundsViewCheck;
 import com.google.android.apps.common.testing.accessibility.framework.EditableContentDescViewCheck;
+import com.google.android.apps.common.testing.accessibility.framework.SpeakableTextPresentInfoCheck;
+import com.google.android.apps.common.testing.accessibility.framework.SpeakableTextPresentViewCheck;
 import com.google.android.apps.common.testing.accessibility.framework.TouchTargetSizeViewCheck;
 
 import org.junit.Assert;
@@ -71,14 +73,20 @@
         //                                     should not both be clickable. Some examples in:
         //                                     PageInfoRowView, AutofillAssistant and TabModal.
         //
+        //   SpeakableTextPresent* checks - Some views are failing this test on certain try bots,
+        //                                  so disable this check to reduce churn for sheriffs
+        //                                  until issue can be found. Some examples in:
+        //                                  AccessibilitySettings, ReaderMode, and Feedv2 tests.
+        //
         // TODO(AccessibilityChecks): Complete above audits and ideally suppress no checks.
         try {
             AccessibilityChecks.enable().setSuppressingResultMatcher(anyOf(
                     matchesCheckNames(is(TouchTargetSizeViewCheck.class.getSimpleName())),
                     matchesCheckNames(is(ClickableSpanViewCheck.class.getSimpleName())),
                     matchesCheckNames(is(EditableContentDescViewCheck.class.getSimpleName())),
-                    matchesCheckNames(
-                            is(DuplicateClickableBoundsViewCheck.class.getSimpleName()))));
+                    matchesCheckNames(is(DuplicateClickableBoundsViewCheck.class.getSimpleName())),
+                    matchesCheckNames(is(SpeakableTextPresentInfoCheck.class.getSimpleName())),
+                    matchesCheckNames(is(SpeakableTextPresentViewCheck.class.getSimpleName()))));
         } catch (IllegalStateException e) {
             // Suppress IllegalStateException for AccessibilityChecks already enabled.
         }
diff --git a/base/time/time.h b/base/time/time.h
index 712718d..50fccd59 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -104,6 +104,7 @@
 namespace Windows {
 namespace Foundation {
 struct DateTime;
+struct TimeSpan;
 }  // namespace Foundation
 }  // namespace Windows
 }  // namespace ABI
@@ -129,6 +130,7 @@
   // based on absolute time
   static TimeDelta FromFileTime(FILETIME ft);
   static TimeDelta FromWinrtDateTime(ABI::Windows::Foundation::DateTime dt);
+  static TimeDelta FromWinrtTimeSpan(ABI::Windows::Foundation::TimeSpan ts);
 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   static TimeDelta FromTimeSpec(const timespec& ts);
 #endif
@@ -200,6 +202,7 @@
 #endif
 #if BUILDFLAG(IS_WIN)
   ABI::Windows::Foundation::DateTime ToWinrtDateTime() const;
+  ABI::Windows::Foundation::TimeSpan ToWinrtTimeSpan() const;
 #endif
 
   // Returns the frequency in Hertz (cycles per second) that has a period of
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
index 4a7faa42..fc5e79c 100644
--- a/base/time/time_win.cc
+++ b/base/time/time_win.cc
@@ -732,6 +732,18 @@
   return date_time;
 }
 
+// static
+TimeDelta TimeDelta::FromWinrtTimeSpan(ABI::Windows::Foundation::TimeSpan ts) {
+  // Duration is 100 ns intervals
+  return Microseconds(ts.Duration / 10);
+}
+
+ABI::Windows::Foundation::TimeSpan TimeDelta::ToWinrtTimeSpan() const {
+  ABI::Windows::Foundation::TimeSpan time_span;
+  time_span.Duration = InMicroseconds() * 10;
+  return time_span;
+}
+
 #if !defined(ARCH_CPU_ARM64)
 namespace time_internal {
 
diff --git a/base/time/time_win_unittest.cc b/base/time/time_win_unittest.cc
index 5626d66..7684d61 100644
--- a/base/time/time_win_unittest.cc
+++ b/base/time/time_win_unittest.cc
@@ -388,6 +388,31 @@
   EXPECT_EQ(100, time_delta.ToWinrtDateTime().UniversalTime);
 }
 
+TEST(TimeDelta, FromWinrtTimeSpan) {
+  ABI::Windows::Foundation::TimeSpan ts;
+  ts.Duration = 0;
+
+  // 0.
+  EXPECT_EQ(TimeDelta(), TimeDelta::FromWinrtTimeSpan(ts));
+
+  ts.Duration = 101;
+
+  // 101 * 100 ns ~= 10.1 microseconds.
+  EXPECT_EQ(Microseconds(10.1), TimeDelta::FromWinrtTimeSpan(ts));
+}
+
+TEST(TimeDelta, ToWinrtTimeSpan) {
+  auto time_delta = Seconds(0);
+
+  // 0.
+  EXPECT_EQ(0, time_delta.ToWinrtTimeSpan().Duration);
+
+  time_delta = Microseconds(10);
+
+  // 10 microseconds = 100 * 100 ns.
+  EXPECT_EQ(100, time_delta.ToWinrtTimeSpan().Duration);
+}
+
 TEST(HighResolutionTimer, GetUsage) {
   Time::ResetHighResolutionTimerUsage();
 
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py
index 57c7c4eb..900ac4d 100755
--- a/build/android/gyp/apkbuilder.py
+++ b/build/android/gyp/apkbuilder.py
@@ -112,12 +112,6 @@
       '--library-always-compress',
       action='append',
       help='The list of library files that we always compress.')
-  # TODO(crbug.com/1337134): Remove all references to --library-renames.
-  # Setting it should be a no-op.
-  parser.add_argument(
-      '--library-renames',
-      action='append',
-      help='The list of library files that we prepend crazy. to their names.')
   parser.add_argument('--warnings-as-errors',
                       action='store_true',
                       help='Treat all warnings as errors.')
@@ -136,7 +130,6 @@
       options.secondary_native_libs)
   options.library_always_compress = build_utils.ParseGnList(
       options.library_always_compress)
-  options.library_renames = build_utils.ParseGnList(options.library_renames)
 
   options.uncompress_shared_libraries = \
       options.uncompress_shared_libraries in [ 'true', 'True' ]
diff --git a/build/android/gyp/assert_static_initializers.py b/build/android/gyp/assert_static_initializers.py
index 3d036b4..92061b8 100755
--- a/build/android/gyp/assert_static_initializers.py
+++ b/build/android/gyp/assert_static_initializers.py
@@ -42,8 +42,8 @@
 
 
 def _DumpStaticInitializers(apk_so_name, unzipped_so, out_dir, tool_prefix):
-  lib_name = os.path.basename(apk_so_name).replace('crazy.', '')
-  so_with_symbols_path = os.path.join(out_dir, 'lib.unstripped', lib_name)
+  so_with_symbols_path = os.path.join(out_dir, 'lib.unstripped',
+                                      os.path.basename(apk_so_name))
   if not os.path.exists(so_with_symbols_path):
     raise Exception('Unstripped .so not found. Looked here: %s' %
                     so_with_symbols_path)
diff --git a/build/android/gyp/create_app_bundle.py b/build/android/gyp/create_app_bundle.py
index 5e68d515..ba67861 100755
--- a/build/android/gyp/create_app_bundle.py
+++ b/build/android/gyp/create_app_bundle.py
@@ -199,13 +199,10 @@
   split_dimensions = [ _MakeSplitDimension(dim, dim in split_dimensions)
                        for dim in _ALL_SPLIT_DIMENSIONS ]
 
-  # Native libraries loaded by the crazy linker.
-  # Whether other .so files are compressed is controlled by
-  # "uncompressNativeLibraries".
-  uncompressed_globs = ['lib/*/crazy.*']
   # Locale-specific pak files stored in bundle splits need not be compressed.
-  uncompressed_globs.extend(
-      ['assets/locales#lang_*/*.pak', 'assets/fallback-locales/*.pak'])
+  uncompressed_globs = [
+      'assets/locales#lang_*/*.pak', 'assets/fallback-locales/*.pak'
+  ]
   uncompressed_globs.extend('assets/' + x for x in uncompressed_assets)
   # NOTE: Use '**' instead of '*' to work through directories!
   uncompressed_globs.extend('**.' + ext for ext in _UNCOMPRESSED_FILE_EXTS)
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 4c4a159..2fcbf04 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -411,9 +411,6 @@
 * `native['library_always_compress']`
 A list of library files that we always compress.
 
-* `native['library_renames']`
-A list of library files that we prepend "crazy." to their file names.
-
 * `assets`
 A list of assets stored compressed in the APK. Each entry has the format
 `<source-path>:<destination-path>`, where `<source-path>` is relative to
@@ -1101,10 +1098,6 @@
   parser.add_option(
       '--library-always-compress',
       help='The list of library files that we always compress.')
-  parser.add_option(
-      '--library-renames',
-      default=[],
-      help='The list of library files that we prepend crazy. to their names.')
 
   # apk options
   parser.add_option('--apk-path', help='Path to the target\'s apk output.')
@@ -1243,10 +1236,6 @@
       raise Exception(
           '--library-always-compress can only be used with --type=android_apk '
           'or --type=android_app_bundle_module')
-    if options.library_renames:
-      raise Exception(
-          '--library-renames can only be used with --type=android_apk or '
-          '--type=android_app_bundle_module')
 
   if options.device_jar_path and not options.dex_path:
     raise Exception('java_library that supports Android requires a dex path.')
@@ -2078,8 +2067,6 @@
         options.uncompress_shared_libraries,
         'library_always_compress':
         options.library_always_compress,
-        'library_renames':
-        options.library_renames,
         'loadable_modules':
         loadable_modules,
         'secondary_abi_loadable_modules':
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 6d8b674..404d683 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -471,10 +471,6 @@
       args += [ "--library-always-compress=${invoker.library_always_compress}" ]
     }
 
-    if (defined(invoker.library_renames)) {
-      args += [ "--library-renames=${invoker.library_renames}" ]
-    }
-
     if (defined(invoker.apk_path)) {
       # TODO(tiborg): Remove APK path from build config and use
       # install_artifacts from metadata instead.
@@ -2823,9 +2819,6 @@
       _args +=
           [ "--library-always-compress=${invoker.library_always_compress}" ]
     }
-    if (defined(invoker.library_renames)) {
-      _args += [ "--library-renames=${invoker.library_renames}" ]
-    }
     if (defined(invoker.dex_path)) {
       _inputs += [ invoker.dex_path ]
       _args += [
@@ -3622,7 +3615,6 @@
               "static_library_dependent_targets",
               "uncompress_shared_libraries",
               "library_always_compress",
-              "library_renames",
             ])
       }
       if (_type == "android_apk") {
@@ -4240,7 +4232,6 @@
     "--uncompress-shared-libraries=@FileArg(" +
         "$_rebased_build_config:native:uncompress_shared_libraries)",
     "--library-always-compress=@FileArg($_rebased_build_config:native:library_always_compress)",
-    "--library-renames=@FileArg($_rebased_build_config:native:library_renames)",
   ]
   if (defined(android_app_secondary_abi)) {
     _rebased_secondary_abi_native_libraries_config =
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 15e41811..9661911 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -3128,7 +3128,6 @@
                                "sources",
                                "static_library_dependent_targets",
                                "library_always_compress",
-                               "library_renames",
                              ])
       if (_uses_static_library_synchronized_proguard) {
         if (!defined(jar_excluded_patterns)) {
@@ -3463,7 +3462,6 @@
                                  "uncompress_dex",
                                  "uncompress_shared_libraries",
                                  "library_always_compress",
-                                 "library_renames",
                                ])
 
         if (defined(expected_libs_and_assets)) {
@@ -3817,7 +3815,6 @@
                                "uncompress_dex",
                                "uncompress_shared_libraries",
                                "library_always_compress",
-                               "library_renames",
                                "use_chromium_linker",
                                "version_code",
                                "version_name",
@@ -3948,7 +3945,6 @@
                                "testonly",
                                "uncompress_shared_libraries",
                                "library_always_compress",
-                               "library_renames",
                                "use_chromium_linker",
                                "use_modern_linker",
                                "uses_split",
@@ -4966,8 +4962,7 @@
   #      used as a library jar for synchronized proguarding.
   #
   #    compress_shared_libraries: Optional. Whether to compress shared libraries
-  #      such that they are extracted upon install. Libraries prefixed with
-  #      "crazy." are never compressed.
+  #      such that they are extracted upon install.
   #
   #    system_image_locale_allowlist: List of locales that should be included
   #      on system APKs generated from this bundle.
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index b1e5b39..7183544 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -861,6 +861,10 @@
     # we discover a reason to turn them off.
     "-Coverflow-checks=on",
 
+    # Turn warnings into the "deny" lint level, which produce compiler errors.
+    # The equivalent of -Werror for clang/gcc.
+    "-Dwarnings",
+
     # To make Rust .d files compatible with ninja
     "-Zdep-info-omit-d-target",
 
diff --git a/build/fuchsia/device_target.py b/build/fuchsia/device_target.py
index ced6e8a..8f2c48f 100644
--- a/build/fuchsia/device_target.py
+++ b/build/fuchsia/device_target.py
@@ -4,6 +4,7 @@
 
 """Implements commands for running and interacting with Fuchsia on devices."""
 
+import errno
 import itertools
 import logging
 import os
@@ -18,11 +19,11 @@
 import ffx_session
 
 from common import ATTACH_RETRY_SECONDS, EnsurePathExists, \
-                   GetHostToolPathFromPlatform, RunGnSdkFunction
+                   GetHostToolPathFromPlatform, RunGnSdkFunction, SDK_ROOT
 
 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),
                                              'test')))
-from compatible_utils import get_sdk_hash, pave
+from compatible_utils import get_sdk_hash, pave, find_image_in_sdk
 
 # The maximum times to attempt mDNS resolution when connecting to a freshly
 # booted Fuchsia instance before aborting.
@@ -103,8 +104,25 @@
     self._target_context = None
     self._ffx_target = None
     self._ermine_ctl = legacy_ermine_ctl.LegacyErmineCtl(self)
-    if not self._system_image_dir and self._os_check != 'ignore':
-      raise Exception("Image directory must be provided if a repave is needed.")
+
+    if self._os_check != 'ignore':
+      if not self._system_image_dir:
+        raise Exception(
+            "Image directory must be provided if a repave is needed.")
+      # Determine if system_image_dir exists and find dynamically if not.
+      if not os.path.exists(system_image_dir):
+        logging.warning('System image dir does not exist. Assuming it\'s a '
+                        'product-bundle and dynamically searching for it')
+        sdk_root_parent = os.path.split(SDK_ROOT)[0]
+        new_dir = find_image_in_sdk(system_image_dir,
+                                    product_bundle=True,
+                                    sdk_root=sdk_root_parent)
+        if not new_dir:
+          raise FileNotFoundError(
+              errno.ENOENT,
+              'Could not find system image directory in SDK path ' +
+              sdk_root_parent, system_image_dir)
+        self._system_image_dir = new_dir
 
     if self._host and self._node_name:
       raise Exception('Only one of "--host" or "--name" can be specified.')
diff --git a/build/fuchsia/device_target_test.py b/build/fuchsia/device_target_test.py
index 79c1938..04c4d0d 100755
--- a/build/fuchsia/device_target_test.py
+++ b/build/fuchsia/device_target_test.py
@@ -152,7 +152,8 @@
       self.assertIsNone(device_target_instance._host)
     mock_daemon_stop.assert_called_once()
 
-  def testNoProvisionDeviceIfVersionsMatch(self, mock_daemon_stop):
+  @mock.patch('os.path.exists', return_value=True)
+  def testNoProvisionDeviceIfVersionsMatch(self, unused_mock, mock_daemon_stop):
     self.args.os_check = 'update'
     self.args.system_image_dir = 'mockdir'
     with DeviceTarget.CreateFromArgs(self.args) as device_target_instance, \
@@ -173,7 +174,9 @@
       mock_login.assert_called_once()
     mock_daemon_stop.assert_called_once()
 
-  def testRaiseExceptionIfCheckVersionsNoMatch(self, mock_daemon_stop):
+  @mock.patch('os.path.exists', return_value=True)
+  def testRaiseExceptionIfCheckVersionsNoMatch(self, unused_mock,
+                                               mock_daemon_stop):
     self.args.os_check = 'check'
     self.args.system_image_dir = 'mockdir'
     with DeviceTarget.CreateFromArgs(self.args) as device_target_instance, \
@@ -216,7 +219,9 @@
       mock_exists.assert_called_once()
       self.assertEqual(mock_shell.call_count, 0)
 
-  def testProvisionIfOneNonDetectableDevice(self, mock_daemon_stop):
+  @mock.patch('os.path.exists', return_value=True)
+  def testProvisionIfOneNonDetectableDevice(self, unused_mock,
+                                            mock_daemon_stop):
     self.args.os_check = 'update'
     self.args.node_name = 'mocknode'
     self.args.system_image_dir = 'mockdir'
@@ -231,6 +236,37 @@
       self.assertEqual(mock_provision.call_count, 1)
     mock_daemon_stop.assert_called_once()
 
+  def testRaiseExceptionIfNoTargetDir(self, mock_daemon_stop):
+    self.args.os_check = 'update'
+    self.args.system_image_dir = ''
+    with self.assertRaises(Exception):
+      DeviceTarget.CreateFromArgs(self.args)
+
+  def testSearchSDKIfImageDirNotFound(self, mock_daemon_stop):
+    self.args.os_check = 'update'
+    self.args.system_image_dir = 'product-bundle-instead-of-image'
+    with mock.patch('os.path.exists', return_value=False), \
+        mock.patch('device_target.find_image_in_sdk',
+                   return_value='some/path/to/image') as mock_find, \
+        mock.patch('device_target.SDK_ROOT', 'some/path/to/sdk'), \
+        self.assertLogs():
+      target = DeviceTarget.CreateFromArgs(self.args)
+      mock_find.assert_called_once_with('product-bundle-instead-of-image',
+                                        product_bundle=True,
+                                        sdk_root='some/path/to')
+      self.assertEqual(target._system_image_dir, 'some/path/to/image')
+
+  def testSearchSDKThrowsExceptionIfNoPathReturned(self, mock_daemon_stop):
+    self.args.os_check = 'update'
+    self.args.system_image_dir = 'product-bundle-instead-of-image'
+    with mock.patch('os.path.exists', return_value=False), \
+        mock.patch('device_target.find_image_in_sdk',
+                   return_value=None), \
+        mock.patch('device_target.SDK_ROOT', 'some/path/to/sdk'), \
+        self.assertLogs(), \
+        self.assertRaises(FileNotFoundError):
+      target = DeviceTarget.CreateFromArgs(self.args)
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index e7bea22..780d7315 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-10.20221121.3.1
+10.20221122.0.1
diff --git a/build/fuchsia/test/common.py b/build/fuchsia/test/common.py
index ebaefb76..64e08f6 100644
--- a/build/fuchsia/test/common.py
+++ b/build/fuchsia/test/common.py
@@ -6,7 +6,6 @@
 import json
 import logging
 import os
-import platform
 import re
 import subprocess
 import time
@@ -14,25 +13,13 @@
 from argparse import ArgumentParser
 from typing import Iterable, List, Optional
 
-from compatible_utils import get_ssh_prefix
+from compatible_utils import get_ssh_prefix, get_host_arch
 
 DIR_SRC_ROOT = os.path.abspath(
     os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
 REPO_ALIAS = 'fuchsia.com'
 SDK_ROOT = os.path.join(DIR_SRC_ROOT, 'third_party', 'fuchsia-sdk', 'sdk')
 
-
-def get_host_arch() -> str:
-    """Retrieve CPU architecture of the host machine. """
-    host_arch = platform.machine()
-    # platform.machine() returns AMD64 on 64-bit Windows.
-    if host_arch in ['x86_64', 'AMD64']:
-        return 'x64'
-    if host_arch == 'aarch64':
-        return 'arm64'
-    raise Exception('Unsupported host architecture: %s' % host_arch)
-
-
 SDK_TOOLS_DIR = os.path.join(SDK_ROOT, 'tools', get_host_arch())
 _FFX_TOOL = os.path.join(SDK_TOOLS_DIR, 'ffx')
 
diff --git a/build/fuchsia/test/compatible_utils.py b/build/fuchsia/test/compatible_utils.py
index c86af343..d5cdc82 100644
--- a/build/fuchsia/test/compatible_utils.py
+++ b/build/fuchsia/test/compatible_utils.py
@@ -4,7 +4,9 @@
 """Functions used in both v1 and v2 scripts."""
 
 import os
+import platform
 import re
+import stat
 import subprocess
 
 from typing import List, Optional, Tuple
@@ -12,6 +14,7 @@
 
 # File indicating version of an image downloaded to the host
 _BUILD_ARGS = "buildargs.gn"
+_ARGS_FILE = 'args.gn'
 
 _FILTER_DIR = 'testing/buildbot/filters'
 _SSH_KEYS = os.path.expanduser('~/.ssh/fuchsia_authorized_keys')
@@ -37,10 +40,52 @@
     return 'CHROME_HEADLESS' in os.environ
 
 
+def get_host_arch() -> str:
+    """Retrieve CPU architecture of the host machine. """
+    host_arch = platform.machine()
+    # platform.machine() returns AMD64 on 64-bit Windows.
+    if host_arch in ['x86_64', 'AMD64']:
+        return 'x64'
+    if host_arch == 'aarch64':
+        return 'arm64'
+    raise NotImplementedError('Unsupported host architecture: %s' % host_arch)
+
+
+def add_exec_to_file(file: str) -> None:
+    """Add execution bits to a file.
+
+    Args:
+        file: path to the file.
+    """
+    file_stat = os.stat(file)
+    os.chmod(file, file_stat.st_mode | stat.S_IXUSR)
+
+
+def _add_exec_to_pave_binaries(system_image_dir: str):
+    """Add exec to required pave files.
+
+    The pave files may vary depending if a product-bundle or a prebuilt images
+    directory is being used.
+    Args:
+      system_image_dir: string path to the directory containing the pave files.
+    """
+    pb_files = [
+        'pave.sh',
+        os.path.join(f'host_{get_host_arch()}', 'bootserver')
+    ]
+    image_files = [
+        'pave.sh',
+        os.path.join(f'bootserver.exe.linux-{get_host_arch()}')
+    ]
+    use_pb_files = os.path.exists(os.path.join(system_image_dir, pb_files[1]))
+    for f in pb_files if use_pb_files else image_files:
+        add_exec_to_file(os.path.join(system_image_dir, f))
+
+
 def pave(image_dir: str, target_id: Optional[str])\
         -> subprocess.CompletedProcess:
     """"Pave a device using the pave script inside |image_dir|."""
-
+    _add_exec_to_pave_binaries(image_dir)
     pave_command = [
         os.path.join(image_dir, 'pave.sh'), '--authorized-keys',
         get_ssh_keys(), '-1'
@@ -105,10 +150,19 @@
     """
 
     # TODO(crbug.com/1261961): Stop processing buildargs.gn directly.
-    with open(os.path.join(system_image_dir, _BUILD_ARGS)) as f:
+    args_file = os.path.join(system_image_dir, _BUILD_ARGS)
+    if not os.path.exists(args_file):
+        args_file = os.path.join(system_image_dir, _ARGS_FILE)
+
+    if not os.path.exists(args_file):
+        raise VersionNotFoundError(
+            f'Dir {system_image_dir} did not contain {_BUILD_ARGS} or '
+            f'{_ARGS_FILE}')
+
+    with open(args_file) as f:
         contents = f.readlines()
     if not contents:
-        raise VersionNotFoundError('Could not retrieve %s' % _BUILD_ARGS)
+        raise VersionNotFoundError('Could not retrieve %s' % args_file)
     version_key = 'build_info_version'
     product_key = 'build_info_product'
     info_keys = [product_key, version_key]
@@ -121,6 +175,64 @@
     if not (version_key in version_info and product_key in version_info):
         raise VersionNotFoundError(
             'Could not extract version info from %s. Contents: %s' %
-            (_BUILD_ARGS, contents))
+            (args_file, contents))
 
     return (version_info[product_key], version_info[version_key])
+
+
+def find_in_dir(target_name: str,
+                parent_dir: str,
+                search_for_dir: bool = False) -> Optional[str]:
+    """Finds path in SDK.
+
+    Args:
+      target_name: Name of target to find, as a string.
+      parent_dir: Directory to start search in.
+      search_for_dir: boolean, whether to search for a directory or file.
+
+    Returns:
+      Optional full path to the target, if found. None if not found.
+    """
+    # Doesn't make sense to look for a full path. Only extract the basename.
+    target_name = os.path.basename(target_name)
+    for root, dirs, files in os.walk(parent_dir):
+        # Removing these parens causes the following equivalent operation order:
+        # if (target_name in dirs) if search_for_dir else files, which is
+        # incorrect.
+        #pylint: disable=superfluous-parens
+        if target_name in (dirs if search_for_dir else files):
+            return os.path.abspath(os.path.join(root, target_name))
+        #pylint: enable=superfluous-parens
+
+    return None
+
+
+def find_image_in_sdk(product_name: str, product_bundle: bool,
+                      sdk_root: str) -> Optional[str]:
+    """Finds image dir in SDK for product given.
+
+    Args:
+      product_name: Name of product's image directory to find.
+      product_bundle: boolean, whether image will be in a product-bundle or not.
+        Product bundle images use a different directory format.
+      sdk_root: String path to root of SDK (third_party/fuchsia-sdk).
+
+    Returns:
+      Optional full path to the target, if found. None if not found.
+    """
+    if product_bundle:
+        top_image_dir = os.path.join(sdk_root, 'images')
+        path = find_in_dir(product_name,
+                           parent_dir=top_image_dir,
+                           search_for_dir=True)
+        return find_in_dir('images', parent_dir=path, search_for_dir=True)
+
+    # Non-product-bundle directories take some massaging.
+    top_image_dir = os.path.join(sdk_root, 'images-internal')
+    product, board = product_name.split('.')
+    board_dir = find_in_dir(board,
+                            parent_dir=top_image_dir,
+                            search_for_dir=True)
+
+    #  The board dir IS the images dir
+    return find_in_dir(product, parent_dir=board_dir, search_for_dir=True)
diff --git a/build/fuchsia/test/compatible_utils_unittests.py b/build/fuchsia/test/compatible_utils_unittests.py
new file mode 100755
index 0000000..080cdda
--- /dev/null
+++ b/build/fuchsia/test/compatible_utils_unittests.py
@@ -0,0 +1,268 @@
+#!/usr/bin/env vpython3
+# 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.
+"""File for testing compatible_utils.py."""
+
+import io
+import os
+import stat
+import tempfile
+import unittest
+import unittest.mock as mock
+
+import compatible_utils
+
+
+class CompatibleUtilsTest(unittest.TestCase):
+    """Test compatible_utils.py methods."""
+
+    def test_running_unattended_returns_true_if_headless_set(self) -> None:
+        """Test |running_unattended| returns True if CHROME_HEADLESS is set."""
+        with mock.patch('os.environ', {'CHROME_HEADLESS': 0}):
+            self.assertTrue(compatible_utils.running_unattended())
+
+        with mock.patch('os.environ', {'FOO_HEADLESS': 0}):
+            self.assertFalse(compatible_utils.running_unattended())
+
+    def test_get_host_arch(self) -> None:
+        """Test |get_host_arch| gets the host architecture and throws
+        exceptions on errors."""
+        supported_arches = ['x86_64', 'AMD64', 'aarch64']
+        with mock.patch('platform.machine', side_effect=supported_arches):
+            self.assertEqual(compatible_utils.get_host_arch(), 'x64')
+            self.assertEqual(compatible_utils.get_host_arch(), 'x64')
+            self.assertEqual(compatible_utils.get_host_arch(), 'arm64')
+
+        with mock.patch('platform.machine', return_value=['fake-arch']), \
+                self.assertRaises(NotImplementedError):
+            compatible_utils.get_host_arch()
+
+    def test_add_exec_to_file(self) -> None:
+        """Test |add_exec_to_file| adds executable bit to file."""
+        with tempfile.NamedTemporaryFile() as f:
+            original_stat = os.stat(f.name).st_mode
+            self.assertFalse(original_stat & stat.S_IXUSR)
+
+            compatible_utils.add_exec_to_file(f.name)
+
+            new_stat = os.stat(f.name).st_mode
+            self.assertTrue(new_stat & stat.S_IXUSR)
+
+    # pylint: disable=no-self-use
+    def test_pave_adds_exec_to_binary_files(self) -> None:
+        """Test |pave| calls |add_exec_to_file| on necessary files."""
+        with mock.patch('os.path.exists', return_value=True), \
+                mock.patch('compatible_utils.add_exec_to_file') as mock_exec, \
+                mock.patch('platform.machine', return_value='x86_64'), \
+                mock.patch('subprocess.run'):
+            compatible_utils.pave('some/path/to/dir', 'some-target')
+
+            mock_exec.assert_has_calls([
+                mock.call('some/path/to/dir/pave.sh'),
+                mock.call('some/path/to/dir/host_x64/bootserver')
+            ],
+                                       any_order=True)
+
+    def test_pave_adds_exec_to_binary_files_if_pb_set_not_found(self) -> None:
+        """Test |pave| calls |add_exec_to_file| on necessary files.
+
+        Checks if current product-bundle files exist. If not, defaults to
+        prebuilt-images set.
+        """
+        with mock.patch('os.path.exists', return_value=False), \
+                mock.patch('compatible_utils.add_exec_to_file') as mock_exec, \
+                mock.patch('platform.machine', return_value='x86_64'), \
+                mock.patch('subprocess.run'):
+            compatible_utils.pave('some/path/to/dir', 'some-target')
+
+            mock_exec.assert_has_calls([
+                mock.call('some/path/to/dir/pave.sh'),
+                mock.call('some/path/to/dir/bootserver.exe.linux-x64')
+            ],
+                                       any_order=True)
+
+    def test_pave_adds_target_id_if_given(self) -> None:
+        """Test |pave| adds target-id to the arguments."""
+        with mock.patch('os.path.exists', return_value=False), \
+                mock.patch('compatible_utils.add_exec_to_file'), \
+                mock.patch('platform.machine', return_value='x86_64'), \
+                mock.patch('compatible_utils.get_ssh_keys',
+                           return_value='authorized-keys-file'), \
+                mock.patch('subprocess.run') as mock_subproc:
+            mock_subproc.reset_mock()
+            compatible_utils.pave('some/path/to/dir', 'some-target')
+
+            mock_subproc.assert_called_once_with([
+                'some/path/to/dir/pave.sh', '--authorized-keys',
+                'authorized-keys-file', '-1', '-n', 'some-target'
+            ],
+                                                 check=True,
+                                                 text=True,
+                                                 timeout=300)
+
+    # pylint: disable=no-self-use
+
+    def test_parse_host_port_splits_address_and_strips_brackets(self) -> None:
+        """Test |parse_host_port| splits ipv4 and ipv6 addresses correctly."""
+        self.assertEqual(compatible_utils.parse_host_port('hostname:55'),
+                         ('hostname', 55))
+        self.assertEqual(compatible_utils.parse_host_port('192.168.42.40:443'),
+                         ('192.168.42.40', 443))
+        self.assertEqual(
+            compatible_utils.parse_host_port('[2001:db8::1]:8080'),
+            ('2001:db8::1', 8080))
+
+    def test_map_filter_filter_file_throws_value_error_if_wrong_path(self
+                                                                     ) -> None:
+        """Test |map_filter_file| throws ValueError if path is missing
+        FILTER_DIR."""
+        with self.assertRaises(ValueError):
+            compatible_utils.map_filter_file_to_package_file('foo')
+
+        with self.assertRaises(ValueError):
+            compatible_utils.map_filter_file_to_package_file('some/other/path')
+
+        with self.assertRaises(ValueError):
+            compatible_utils.map_filter_file_to_package_file('filters/file')
+
+        # No error.
+        compatible_utils.map_filter_file_to_package_file(
+            'testing/buildbot/filters/some.filter')
+
+    def test_map_filter_filter_replaces_filter_dir_with_pkg_path(self) -> None:
+        """Test |map_filter_file| throws ValueError if path is missing
+        FILTER_DIR."""
+        self.assertEqual(
+            '/pkg/testing/buildbot/filters/some.filter',
+            compatible_utils.map_filter_file_to_package_file(
+                'foo/testing/buildbot/filters/some.filter'))
+
+    def test_get_sdk_hash_fallsback_to_args_file_if_buildargs_dne(self
+                                                                  ) -> None:
+        """Test |get_sdk_hash| checks if buildargs.gn exists.
+
+        If it does not, fallsback to args.gn. This should raise an exception
+        as it does not exist.
+        """
+        with mock.patch('os.path.exists', return_value=False) as mock_exists, \
+                self.assertRaises(compatible_utils.VersionNotFoundError):
+            compatible_utils.get_sdk_hash('some/image/dir')
+        mock_exists.assert_has_calls([
+            mock.call('some/image/dir/buildargs.gn'),
+            mock.call('some/image/dir/args.gn')
+        ])
+
+    def test_get_sdk_hash_parse_contents_of_args_file(self) -> None:
+        """Test |get_sdk_hash| parses buildargs contents correctly."""
+        build_args_test_contents = """
+build_info_board = "chromebook-x64"
+build_info_product = "workstation_eng"
+build_info_version = "10.20221114.2.1"
+universe_package_labels += []
+"""
+        with mock.patch('os.path.exists', return_value=True), \
+                mock.patch('builtins.open',
+                           return_value=io.StringIO(build_args_test_contents)):
+            self.assertEqual(compatible_utils.get_sdk_hash('some/dir'),
+                             ('workstation_eng', '10.20221114.2.1'))
+
+    def test_get_sdk_hash_raises_error_if_keys_missing(self) -> None:
+        """Test |get_sdk_hash| raises VersionNotFoundError if missing keys"""
+        build_args_test_contents = """
+import("//boards/chromebook-x64.gni")
+import("//products/workstation_eng.gni")
+cxx_rbe_enable = true
+host_labels += [ "//bundles/infra/build" ]
+universe_package_labels += []
+"""
+        with mock.patch('os.path.exists', return_value=True), \
+                mock.patch(
+                    'builtins.open',
+                    return_value=io.StringIO(build_args_test_contents)), \
+                self.assertRaises(compatible_utils.VersionNotFoundError):
+            compatible_utils.get_sdk_hash('some/dir')
+
+    def test_get_sdk_hash_raises_error_if_contents_empty(self) -> None:
+        """Test |get_sdk_hash| raises VersionNotFoundError if no contents."""
+        with mock.patch('os.path.exists', return_value=True), \
+                mock.patch('builtins.open', return_value=io.StringIO("")), \
+                self.assertRaises(compatible_utils.VersionNotFoundError):
+            compatible_utils.get_sdk_hash('some/dir')
+
+    def test_find_in_dir_returns_file_or_dir_if_searching(self) -> None:
+        """Test |find_in_dir| returns files if searching for file, or None."""
+        # Make the directory structure.
+        with tempfile.TemporaryDirectory() as tmp_dir:
+            with tempfile.NamedTemporaryFile(dir=tmp_dir) as tmp_file, \
+                tempfile.TemporaryDirectory(dir=tmp_dir) as inner_tmp_dir:
+
+                # Structure is now:
+                # temp_dir/
+                # temp_dir/inner_dir1
+                # temp_dir/tempfile1
+                self.assertEqual(
+                    compatible_utils.find_in_dir(
+                        os.path.basename(tmp_file.name),
+                        parent_dir=tmp_dir,
+                        search_for_dir=False), tmp_file.name)
+                # File is not a dir, so returns None.
+                self.assertIsNone(
+                    compatible_utils.find_in_dir(os.path.basename(
+                        tmp_file.name),
+                                                 parent_dir=tmp_dir,
+                                                 search_for_dir=True))
+
+                # Repeat for directory.
+                self.assertEqual(
+                    compatible_utils.find_in_dir(inner_tmp_dir,
+                                                 parent_dir=tmp_dir,
+                                                 search_for_dir=True),
+                    inner_tmp_dir)
+                self.assertIsNone(
+                    compatible_utils.find_in_dir(inner_tmp_dir,
+                                                 parent_dir=tmp_dir,
+                                                 search_for_dir=False))
+                with tempfile.NamedTemporaryFile(
+                        dir=inner_tmp_dir) as inner_tmp_file:
+                    self.assertEqual(
+                        compatible_utils.find_in_dir(
+                            os.path.basename(inner_tmp_file.name),
+                            parent_dir=tmp_dir,
+                            search_for_dir=False), inner_tmp_file.name)
+                    self.assertEqual(
+                        compatible_utils.find_in_dir(
+                            os.path.basename(inner_tmp_file.name),
+                            parent_dir=inner_tmp_dir,
+                            search_for_dir=False), inner_tmp_file.name)
+
+    def test_find_image_in_sdk_searches_images_in_product_bundle(self):
+        """Test |find_image_in_sdk| searches for 'images' if product-bundle."""
+        with tempfile.TemporaryDirectory() as tmp_dir:
+            os.makedirs(os.path.join(tmp_dir, 'images', 'workstation-product',
+                                     'images'),
+                        exist_ok=True)
+            self.assertEqual(
+                compatible_utils.find_image_in_sdk('workstation-product',
+                                                   product_bundle=True,
+                                                   sdk_root=tmp_dir),
+                os.path.join(tmp_dir, 'images', 'workstation-product',
+                             'images'))
+
+    def test_find_image_in_sdk_searches_images_in_prebuilt(self):
+        """Test |find_image_in_sdk| searches dir if not product-bundle."""
+        with tempfile.TemporaryDirectory() as tmp_dir:
+            os.makedirs(os.path.join(tmp_dir, 'images-internal',
+                                     'chromebook-x64', 'workstation_eng'),
+                        exist_ok=True)
+            self.assertEqual(
+                compatible_utils.find_image_in_sdk(
+                    'workstation_eng.chromebook-x64',
+                    product_bundle=False,
+                    sdk_root=tmp_dir),
+                os.path.join(tmp_dir, 'images-internal', 'chromebook-x64',
+                             'workstation_eng'))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/build/fuchsia/test/coveragetest.py b/build/fuchsia/test/coveragetest.py
index 5c762a5..4c779be 100755
--- a/build/fuchsia/test/coveragetest.py
+++ b/build/fuchsia/test/coveragetest.py
@@ -13,7 +13,7 @@
 
 COVERED_FILES = [
     'flash_device.py', 'log_manager.py', 'publish_package.py', 'serve_repo.py',
-    'test_server.py'
+    'test_server.py', 'compatible_utils.py'
 ]
 
 
diff --git a/build/fuchsia/test/ffx_integration.py b/build/fuchsia/test/ffx_integration.py
index 01b5d9a..d93869fd 100644
--- a/build/fuchsia/test/ffx_integration.py
+++ b/build/fuchsia/test/ffx_integration.py
@@ -14,8 +14,9 @@
 from contextlib import AbstractContextManager
 from typing import Iterable, Optional
 
-from common import get_host_arch, run_ffx_command, run_continuous_ffx_command, \
+from common import run_ffx_command, run_continuous_ffx_command, \
                    SDK_ROOT
+from compatible_utils import get_host_arch
 
 _EMU_COMMAND_RETRIES = 3
 RUN_SUMMARY_SCHEMA = \
diff --git a/build/fuchsia/test/flash_device.py b/build/fuchsia/test/flash_device.py
index db4b382..159ed7c4 100755
--- a/build/fuchsia/test/flash_device.py
+++ b/build/fuchsia/test/flash_device.py
@@ -6,6 +6,7 @@
 
 import argparse
 import json
+import logging
 import os
 import subprocess
 import sys
@@ -13,9 +14,9 @@
 
 from typing import Optional, Tuple
 
-from common import register_device_args, run_ffx_command
+from common import register_device_args, run_ffx_command, SDK_ROOT
 from compatible_utils import get_sdk_hash, get_ssh_keys, pave, \
-    running_unattended
+    running_unattended, add_exec_to_file, get_host_arch, find_image_in_sdk
 from ffx_integration import ScopedFfxConfig
 
 
@@ -42,22 +43,57 @@
 
 
 def update_required(os_check, system_image_dir: Optional[str],
-                    target: Optional[str]) -> bool:
-    """Returns True if a system updated is required."""
+                    target: Optional[str]) -> Tuple[bool, Optional[str]]:
+    """Returns True if a system update is required and path to image dir."""
 
     if os_check == 'ignore':
-        return False
+        return False, system_image_dir
     if not system_image_dir:
         raise ValueError('System image directory must be specified.')
+    if not os.path.exists(system_image_dir):
+        logging.warning(
+            'System image directory does not exist. Assuming it\'s '
+            'a product-bundle name and dynamically searching for '
+            'image directory')
+        # SDK_ROOT points to third_party/fuchsia-sdk/sdk, but we want the root
+        # of the overall fuchsia-sdk package.
+        sdk_root_parent = os.path.split(SDK_ROOT)[0]
+        path = find_image_in_sdk(system_image_dir,
+                                 product_bundle=True,
+                                 sdk_root=sdk_root_parent)
+        if not path:
+            raise FileNotFoundError(
+                f'System image directory {system_image_dir} could not'
+                'be found')
+        system_image_dir = path
     if (os_check == 'check'
             and get_sdk_hash(system_image_dir) == _get_system_info(target)):
-        return False
-    return True
+        return False, system_image_dir
+    return True, system_image_dir
+
+
+def _add_exec_to_flash_binaries(system_image_dir: str) -> None:
+    """Add exec to required flash files.
+
+    The flash files may vary depending if a product-bundle or a prebuilt images
+    directory is being used.
+    Args:
+      system_image_dir: string path to the directory containing the flash files.
+    """
+    pb_files = [
+        'flash.sh',
+        os.path.join(f'host_{get_host_arch()}', 'fastboot')
+    ]
+    image_files = ['flash.sh', f'fastboot.exe.linux-{get_host_arch()}']
+    use_pb_files = os.path.exists(os.path.join(system_image_dir, pb_files[1]))
+    for f in pb_files if use_pb_files else image_files:
+        add_exec_to_file(os.path.join(system_image_dir, f))
 
 
 def _run_flash_command(system_image_dir: str, target_id: Optional[str]):
     """Helper function for running `ffx target flash`."""
 
+    _add_exec_to_flash_binaries(system_image_dir)
     # TODO(fxb/91843): Remove workaround when ffx has stable support for
     # multiple hardware devices connected via USB.
     if running_unattended():
@@ -114,8 +150,11 @@
         serial_num: String of serial number of device that should be updated.
         should_pave: Optional bool on whether or not to pave or flash.
     """
+    needs_update, actual_image_dir = update_required(os_check,
+                                                     system_image_dir, target)
 
-    if update_required(os_check, system_image_dir, target):
+    system_image_dir = actual_image_dir
+    if needs_update:
         if should_pave:
             if running_unattended():
                 assert target, ('Target ID must be specified on swarming when'
@@ -130,7 +169,6 @@
                          default_os_check: Optional[str] = 'check',
                          default_pave: Optional[bool] = True) -> None:
     """Register common arguments for device updating."""
-
     serve_args = arg_parser.add_argument_group('update',
                                                'device updating arguments')
     serve_args.add_argument('--system-image-dir',
diff --git a/build/fuchsia/test/flash_device_unittests.py b/build/fuchsia/test/flash_device_unittests.py
index 675bbcc..4b69b01 100755
--- a/build/fuchsia/test/flash_device_unittests.py
+++ b/build/fuchsia/test/flash_device_unittests.py
@@ -37,6 +37,55 @@
         self.addCleanup(self._ffx_mock.stop)
         self.addCleanup(self._sdk_hash_mock.stop)
 
+    def test_update_required_on_ignore_returns_immediately(self) -> None:
+        """Test |os_check|='ignore' skips all checks."""
+        result, new_image_dir = flash_device.update_required(
+            'ignore', 'some-image-dir', None)
+
+        self.assertFalse(result)
+        self.assertEqual(new_image_dir, 'some-image-dir')
+
+    def test_update_required_raises_value_error_if_no_image_dir(self) -> None:
+        """Test |os_check|!='ignore' checks that image dir is non-Falsey."""
+        with self.assertRaises(ValueError):
+            flash_device.update_required('update', None, None)
+
+    def test_update_required_logs_missing_image_dir(self) -> None:
+        """Test |os_check|!='ignore' warns if image dir does not exist."""
+        with mock.patch('os.path.exists', return_value=False), \
+                mock.patch('flash_device.find_image_in_sdk'), \
+                mock.patch('flash_device._get_system_info'), \
+                self.assertLogs() as logger:
+            flash_device.update_required('update', 'some/image/dir', None)
+            self.assertIn('image directory does not exist', logger.output[0])
+
+    def test_update_required_searches_and_returns_sdk_if_image_found(self
+                                                                     ) -> None:
+        """Test |os_check|!='ignore' searches for image dir in SDK."""
+        with mock.patch('os.path.exists', return_value=False), \
+                mock.patch('flash_device.find_image_in_sdk') as mock_find, \
+                mock.patch('flash_device._get_system_info'), \
+                mock.patch('flash_device.SDK_ROOT', 'path/to/sdk/dir'), \
+                self.assertLogs():
+            mock_find.return_value = 'path/to/image/dir'
+            update_required, new_image_dir = flash_device.update_required(
+                'update', 'product-bundle', None)
+            self.assertTrue(update_required)
+            self.assertEqual(new_image_dir, 'path/to/image/dir')
+            mock_find.assert_called_once_with('product-bundle',
+                                              product_bundle=True,
+                                              sdk_root='path/to/sdk')
+
+    def test_update_required_raises_file_not_found_error(self) -> None:
+        """Test |os_check|!='ignore' raises FileNotFoundError if no path."""
+        with mock.patch('os.path.exists', return_value=False), \
+                mock.patch('flash_device.find_image_in_sdk',
+                           return_value=None), \
+                mock.patch('flash_device.SDK_ROOT', 'path/to/sdk/dir'), \
+                self.assertLogs(), \
+                self.assertRaises(FileNotFoundError):
+            flash_device.update_required('update', 'product-bundle', None)
+
     def test_update_ignore(self) -> None:
         """Test setting |os_check| to 'ignore'."""
 
@@ -53,35 +102,95 @@
     def test_update_system_info_match(self) -> None:
         """Test no update when |os_check| is 'check' and system info matches."""
 
-        self._ffx_mock.return_value.stdout = \
-            '[{"title": "Build", "child": [{"value": "%s"}, ' \
-            '{"value": "%s"}]}]' % (_TEST_VERSION, _TEST_PRODUCT)
-        flash_device.update(_TEST_IMAGE_DIR, 'check', None)
-        self.assertEqual(self._ffx_mock.call_count, 1)
-        self.assertEqual(self._sdk_hash_mock.call_count, 1)
+        with mock.patch('os.path.exists', return_value=True):
+            self._ffx_mock.return_value.stdout = \
+                '[{"title": "Build", "child": [{"value": "%s"}, ' \
+                '{"value": "%s"}]}]' % (_TEST_VERSION, _TEST_PRODUCT)
+            flash_device.update(_TEST_IMAGE_DIR, 'check', None)
+            self.assertEqual(self._ffx_mock.call_count, 1)
+            self.assertEqual(self._sdk_hash_mock.call_count, 1)
 
     def test_update_system_info_mismatch(self) -> None:
         """Test update when |os_check| is 'check' and system info does not
         match."""
 
-        self._ffx_mock.return_value.stdout = \
-            '[{"title": "Build", "child": [{"value": "wrong.version"}, ' \
-            '{"value": "wrong_product"}]}]'
-        flash_device.update(_TEST_IMAGE_DIR, 'check', None, should_pave=False)
-        self.assertEqual(self._ffx_mock.call_count, 3)
+        with mock.patch('os.path.exists', return_value=True), \
+                mock.patch('flash_device._add_exec_to_flash_binaries'):
+            self._ffx_mock.return_value.stdout = \
+                '[{"title": "Build", "child": [{"value": "wrong.version"}, ' \
+                '{"value": "wrong_product"}]}]'
+            flash_device.update(_TEST_IMAGE_DIR,
+                                'check',
+                                None,
+                                should_pave=False)
+            self.assertEqual(self._ffx_mock.call_count, 3)
+
+    def test_update_system_info_mismatch_adds_exec_to_flash_binaries(self
+                                                                     ) -> None:
+        """Test update adds exec bit to flash binaries if flashing."""
+
+        with mock.patch('os.path.exists', return_value=True), \
+                mock.patch('flash_device.get_host_arch',
+                           return_value='foo_arch'), \
+                mock.patch('flash_device.add_exec_to_file') as add_exec:
+            self._ffx_mock.return_value.stdout = \
+                '[{"title": "Build", "child": [{"value": "wrong.version"}, ' \
+                '{"value": "wrong_product"}]}]'
+            flash_device.update(_TEST_IMAGE_DIR,
+                                'check',
+                                None,
+                                should_pave=False)
+            add_exec.assert_has_calls([
+                mock.call(os.path.join(_TEST_IMAGE_DIR, 'flash.sh')),
+                mock.call(
+                    os.path.join(_TEST_IMAGE_DIR, 'host_foo_arch', 'fastboot'))
+            ],
+                                      any_order=True)
+
+    def test_update_adds_exec_to_flash_binaries_depending_on_location(
+            self) -> None:
+        """Test update adds exec bit to flash binaries if flashing."""
+
+        # First exists is for image dir, second is for fastboot binary.
+        # Missing this fastboot binary means that the test will default to a
+        # different path.
+        with mock.patch('os.path.exists', side_effect=[True, False]), \
+                mock.patch('flash_device.get_host_arch',
+                           return_value='foo_arch'), \
+                mock.patch('flash_device.add_exec_to_file') as add_exec:
+            self._ffx_mock.return_value.stdout = \
+                '[{"title": "Build", "child": [{"value": "wrong.version"}, ' \
+                '{"value": "wrong_product"}]}]'
+            flash_device.update(_TEST_IMAGE_DIR,
+                                'check',
+                                None,
+                                should_pave=False)
+            add_exec.assert_has_calls([
+                mock.call(os.path.join(_TEST_IMAGE_DIR, 'flash.sh')),
+                mock.call(
+                    os.path.join(_TEST_IMAGE_DIR,
+                                 'fastboot.exe.linux-foo_arch'))
+            ],
+                                      any_order=True)
 
     def test_incorrect_target_info(self) -> None:
         """Test update when |os_check| is 'check' and system info was not
         retrieved."""
-
-        self._ffx_mock.return_value.stdout = '[{"title": "badtitle"}]'
-        flash_device.update(_TEST_IMAGE_DIR, 'check', None, should_pave=False)
-        self.assertEqual(self._ffx_mock.call_count, 3)
+        with mock.patch('os.path.exists', return_value=True), \
+                mock.patch('flash_device._add_exec_to_flash_binaries'):
+            self._ffx_mock.return_value.stdout = '[{"title": "badtitle"}]'
+            flash_device.update(_TEST_IMAGE_DIR,
+                                'check',
+                                None,
+                                should_pave=False)
+            self.assertEqual(self._ffx_mock.call_count, 3)
 
     def test_update_with_serial_num(self) -> None:
         """Test update when |serial_num| is specified."""
 
-        with mock.patch('time.sleep'):
+        with mock.patch('time.sleep'), \
+                mock.patch('os.path.exists', return_value=True), \
+                mock.patch('flash_device._add_exec_to_flash_binaries'):
             flash_device.update(_TEST_IMAGE_DIR,
                                 'update',
                                 None,
@@ -93,7 +202,8 @@
     def test_update_calls_paving_if_specified(self) -> None:
         """Test update calls pave if specified."""
         with mock.patch('time.sleep'), \
-            mock.patch('flash_device.pave') as mock_pave:
+                mock.patch('os.path.exists', return_value=True), \
+                mock.patch('flash_device.pave') as mock_pave:
             flash_device.update(_TEST_IMAGE_DIR,
                                 'update',
                                 'some-target-id',
@@ -107,6 +217,7 @@
         """Test update calls pave if specified."""
         with mock.patch('time.sleep'), \
             mock.patch('flash_device.pave'), \
+            mock.patch('os.path.exists', return_value=True), \
             mock.patch('flash_device.running_unattended', return_value=True):
             self.assertRaises(AssertionError,
                               flash_device.update,
@@ -119,6 +230,8 @@
         """Test update on swarming bots."""
 
         with mock.patch('time.sleep'), \
+             mock.patch('os.path.exists', return_value=True), \
+             mock.patch('flash_device._add_exec_to_flash_binaries'), \
              mock.patch('flash_device.running_unattended',
                         return_value = True), \
              mock.patch('subprocess.run'):
diff --git a/build/fuchsia/update_product_bundles.py b/build/fuchsia/update_product_bundles.py
index 5d018b2..d531ac6 100755
--- a/build/fuchsia/update_product_bundles.py
+++ b/build/fuchsia/update_product_bundles.py
@@ -116,6 +116,8 @@
     ffx_runner.run_ffx(
         ('config', 'set', 'pbms.storage.path', common.IMAGES_ROOT))
 
+    logging.debug('Checking for override file')
+
     # TODO(crbug/1380807): Remove when product bundles can be downloaded
     # for custom SDKs without editing metadata
     override_file = os.path.join(os.path.dirname(__file__), 'sdk_override.txt')
@@ -125,55 +127,65 @@
         pb_metadata.append('{sdk.root}/*.json')
       stack.enter_context(
           ffx_runner.scoped_config('pbms.metadata', json.dumps((pb_metadata))))
+      logging.debug('Applied overrides')
 
+    logging.debug('Checking for current signature')
     signature_filename = common.PRODUCT_BUNDLE_SIGNATURE_FILE
     curr_signature = {}
     if os.path.exists(signature_filename):
       with open(signature_filename, 'r') as f:
         curr_signature = json.load(f)
+      logging.debug('Loaded current signature')
 
+    logging.debug('Getting new SDK hash')
     new_sdk_hash = get_hash_from_sdk()
     new_signature = {'sdk_hash': new_sdk_hash}
 
     # If SDK versions match, remove the product bundles that are no longer
     # needed and download missing ones.
     if curr_signature.get('sdk_hash') == new_sdk_hash:
-      curr_signature.get('sdk_hash')
+      logging.debug('SDK hash has not changed')
       new_signature['path'] = curr_signature.get('path')
       new_product_bundle_hash = []
 
       for image in curr_signature.get('images', []):
+        logging.debug('Checking hash for image: %s', image)
         if image in new_product_bundles:
           new_product_bundle_hash.append(image)
         else:
-          logging.info('Removing no longer needed Fuchsia image %s' % image)
+          logging.info('Removing no longer needed Fuchsia image %s', image)
           ffx_runner.run_ffx(('product-bundle', 'remove', '-f', image))
 
       bundles_to_download = set(new_product_bundles) - \
                             set(curr_signature.get('images', []))
       for bundle in bundles_to_download:
+        logging.debug('Downloading image: %s', image)
         download_product_bundle(bundle, ffx_runner)
       new_product_bundle_hash.extend(bundles_to_download)
       new_signature['images'] = new_product_bundle_hash
 
+      logging.debug('Writing bundle signatures')
       with open(signature_filename, 'w') as f:
         f.write(json.dumps(new_signature))
       return 0
 
     # If SDK versions do not match, remove all existing product bundles
     # and download the ones required.
-    for pb in curr_signature.get('images', []):
-      ffx_runner.run_ffx(('product-bundle', 'remove', '-f', pb))
+    logging.debug('Removing all images')
+    ffx_runner.run_ffx(('product-bundle', 'remove', '-a', '-f'))
 
+    logging.debug('Make clean images root')
     curr_subdir = []
     if os.path.exists(common.IMAGES_ROOT):
       curr_subdir = os.listdir(common.IMAGES_ROOT)
     common.MakeCleanDirectory(common.IMAGES_ROOT)
 
     for pb in new_product_bundles:
+      logging.debug('Downloading bundle: %s', pb)
       download_product_bundle(pb, ffx_runner)
     new_signature['images'] = new_product_bundles
 
+    logging.debug('Writing new images signature')
     new_subdir = os.listdir(common.IMAGES_ROOT)
     subdir_diff = set(new_subdir) - set(curr_subdir)
     if len(subdir_diff) != 1:
diff --git a/chrome/VERSION b/chrome/VERSION
index ff306f6..551d0ce 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=110
 MINOR=0
-BUILD=5434
+BUILD=5435
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 3589024..adfa845 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1535,6 +1535,7 @@
       "//base/test:test_support_java",
       "//cc:cc_java",
       "//chrome/android:chrome_java",
+      "//chrome/android/features/keyboard_accessory/public:public_java",
       "//chrome/android/features/start_surface:java_resources",
       "//chrome/android/features/start_surface:public_java",
       "//chrome/android/features/tab_ui:java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 90e8b1e94..6fdaaa42 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -491,6 +491,7 @@
   "java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerImpl.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreMessageController.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreUtils.java",
+  "java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/TabFreezer.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/BrandingSecurityButtonAnimationDelegate.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabBrowserControlsVisibilityDelegate.java",
   "java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 6d16adff..927bb4b 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -118,6 +118,7 @@
   "junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerUnitTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreMessageControllerUnitTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreUtilsUnitTest.java",
+  "junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/TabFreezerUnitTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/BrandingSecurityButtonAnimationDelegateUnitTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarUnitTest.java",
   "junit/src/org/chromium/chrome/browser/customtabs/shadows/ShadowExternalNavigationDelegateImpl.java",
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 541d1cd..42c62b1 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -186,17 +186,6 @@
         "libchrome_crashpad_handler.so",
         "libchromium_android_linker.so",
       ]
-
-      # Adds "crazy." prefix to avoid libraries being extracted when installed.
-      if (use_chromium_linker) {
-        if (!defined(library_renames)) {
-          library_renames = []
-        }
-        library_renames += [
-          "libchrome.so",
-          "libchromefortest.so",
-        ]
-      }
     }
 
     if (dfmify_dev_ui && (_target_type == "android_apk" ||
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index daebb53..e1ada303 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -46,6 +46,7 @@
   "javatests/src/org/chromium/chrome/browser/TabsTest.java",
   "javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java",
   "javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java",
+  "javatests/src/org/chromium/chrome/browser/ViewTransitionPixelTest.java",
   "javatests/src/org/chromium/chrome/browser/VirtualKeyboardResizeTest.java",
   "javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java",
   "javatests/src/org/chromium/chrome/browser/accessibility/FontSizePrefsTest.java",
diff --git a/chrome/android/expectations/chrome_modern_public_bundle.arm64.libs_and_assets.expected b/chrome/android/expectations/chrome_modern_public_bundle.arm64.libs_and_assets.expected
index 5bd3ea9..4999cda 100644
--- a/chrome/android/expectations/chrome_modern_public_bundle.arm64.libs_and_assets.expected
+++ b/chrome/android/expectations/chrome_modern_public_bundle.arm64.libs_and_assets.expected
@@ -1,4 +1,4 @@
-apk_path=lib/arm64-v8a/crazy.libchrome.so, compress=False, alignment=4096
+apk_path=lib/arm64-v8a/libchrome.so, compress=False, alignment=4096
 apk_path=lib/arm64-v8a/libchrome_crashpad_handler.so, compress=True, alignment=0
 apk_path=lib/arm64-v8a/libchromium_android_linker.so, compress=True, alignment=0
 apk_path=lib/arm64-v8a/liboptimization_guide_internal.so, compress=False, alignment=4096
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
index 69d5cdf..bb361d64 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
@@ -184,4 +184,14 @@
     ManualFillingMediator getMediatorForTesting() {
         return mMediator;
     }
+
+    @Override
+    public int getKeyboardExtensionHeight() {
+        return mMediator != null ? mMediator.getKeyboardExtensionHeight() : 0;
+    }
+
+    @Override
+    public void forceShowForTesting() {
+        mMediator.showWhenKeyboardIsVisible();
+    }
 }
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 d03d7264..e209d423 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() && mKeyboardAccessory.hasActiveTab() && !isSoftKeyboardShowing(view);
+        return isInitialized() && !isSoftKeyboardShowing(view) && mKeyboardAccessory.hasActiveTab();
     }
 
     ObservableSupplier<Integer> getBottomInsetSupplier() {
@@ -565,6 +565,16 @@
     }
 
     /**
+     * Returns the amount that the keyboard will be extended by the accessory bar.
+     */
+    public int getKeyboardExtensionHeight() {
+        if (!canExtendKeyboard()) return 0;
+
+        return mActivity.getResources().getDimensionPixelSize(
+                R.dimen.keyboard_accessory_suggestion_height);
+    }
+
+    /**
      * Opens the keyboard which implicitly dismisses the sheet. Without open sheet, this is a NoOp.
      */
     void swapSheetWithKeyboard() {
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 3ac41fd..69ced559 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,6 +99,11 @@
         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/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
index eec8da98..b9ff1cd 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
@@ -31,6 +31,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisableIf;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.ChromeWindow;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
@@ -144,7 +145,7 @@
     @Test
     @MediumTest
     @EnableFeatures({ChromeFeatureList.AUTOFILL_MANUAL_FALLBACK_ANDROID})
-    @DisableIf.Device(type = {UiDisableIf.TABLET}) // https://crbug.com/1182626
+    @DisabledTest(message = "https://crbug.com/1392789, https://crbug.com/1182626")
     public void testFillsSuggestionOnClick() throws TimeoutException {
         loadTestPage(FakeKeyboard::new);
         mHelper.clickNodeAndShowKeyboard("CREDIT_CARD_NAME_FULL", 1);
diff --git a/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java b/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java
index 8179f00f5..f3fc81b 100644
--- a/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java
+++ b/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java
@@ -227,4 +227,17 @@
      * @param confirmedCallback A {@link Runnable} to trigger upon confirmation.
      */
     void confirmOperation(String title, String message, Runnable confirmedCallback);
+
+    /**
+     * Returns the amount that the keyboard will be extended by the filling component when shown.
+     * i.e. The height of any accessories to be shown on top of the keyboard.
+     */
+    int getKeyboardExtensionHeight();
+
+    /**
+     * Will force the accessory to show when the keyboard is shown.
+     * TODO(crbug.com/1385400): Ideally this would live in a test utility like
+     * ManualFillingTestHelper.
+     */
+    void forceShowForTesting();
 }
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index d860a8d..838c565 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -33,11 +33,13 @@
     "java/res/drawable/fake_search_box_text_box_bg_incognito.xml",
     "java/res/drawable/ic_check_googblue_20dp_animated.xml",
     "java/res/drawable/ic_close_tabs_24dp.xml",
+    "java/res/drawable/ic_deselect_all_24dp.xml",
     "java/res/drawable/ic_group_icon_16dp.xml",
     "java/res/drawable/ic_price_alert_blue.xml",
     "java/res/drawable/ic_rating_star_full.xml",
     "java/res/drawable/ic_rating_star_half.xml",
     "java/res/drawable/ic_rating_star_outline.xml",
+    "java/res/drawable/ic_select_all_24dp.xml",
     "java/res/drawable/iph_drag_and_drop_animated_drawable.xml",
     "java/res/drawable/iph_drag_and_drop_drawable.xml",
     "java/res/drawable/price_card_background.xml",
diff --git a/chrome/android/features/tab_ui/java/res/drawable/ic_deselect_all_24dp.xml b/chrome/android/features/tab_ui/java/res/drawable/ic_deselect_all_24dp.xml
new file mode 100644
index 0000000..d183fc4
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/res/drawable/ic_deselect_all_24dp.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="@macro/default_icon_color">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M7.94,5.12L6.49,3.66C8.07,2.61 9.96,2 12,2c5.52,0 10,4.48 10,10c0,2.04 -0.61,3.93 -1.66,5.51l-1.46,-1.46C19.59,14.86 20,13.48 20,12c0,-4.41 -3.59,-8 -8,-8C10.52,4 9.14,4.41 7.94,5.12zM17.66,9.53l-1.41,-1.41l-2.65,2.65l1.41,1.41L17.66,9.53zM19.78,22.61l-2.27,-2.27C15.93,21.39 14.04,22 12,22C6.48,22 2,17.52 2,12c0,-2.04 0.61,-3.93 1.66,-5.51L1.39,4.22l1.41,-1.41l18.38,18.38L19.78,22.61zM16.06,18.88l-3.88,-3.88l-1.59,1.59l-4.24,-4.24l1.41,-1.41l2.83,2.83l0.18,-0.18L5.12,7.94C4.41,9.14 4,10.52 4,12c0,4.41 3.59,8 8,8C13.48,20 14.86,19.59 16.06,18.88z"/>
+</vector>
diff --git a/chrome/android/features/tab_ui/java/res/drawable/ic_select_all_24dp.xml b/chrome/android/features/tab_ui/java/res/drawable/ic_select_all_24dp.xml
new file mode 100644
index 0000000..427d9b60
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/res/drawable/ic_select_all_24dp.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="@macro/default_icon_color">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM10,14.2l-2.6,-2.6L6,13l4,4 8,-8 -1.4,-1.4z"/>
+</vector>
diff --git a/chrome/android/features/tab_ui/java/res/values/dimens.xml b/chrome/android/features/tab_ui/java/res/values/dimens.xml
index fe50f99..ba200e1 100644
--- a/chrome/android/features/tab_ui/java/res/values/dimens.xml
+++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -81,6 +81,5 @@
 
     <!-- Dimens for TabSelectionEditorV2 -->
     <dimen name="tab_selection_editor_action_view_padding">14dp</dimen>
-    <dimen name="tab_selection_editor_selection_action_inset">2dp</dimen>
     <dimen name="tab_selection_editor_share_sheet_preview_thumbnail_padding">10dp</dimen>
 </resources>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
index c77e9bb..c5f71ec 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
@@ -556,9 +556,8 @@
 
         if (TabUiFeatureUtilities.isTabSelectionEditorV2Enabled(mContext)) {
             List<TabSelectionEditorAction> actions = new ArrayList<>();
-            actions.add(TabSelectionEditorSelectionAction.createAction(mContext, ShowMode.MENU_ONLY,
-                    ButtonType.ICON_AND_TEXT, IconPosition.END,
-                    mTabModelSelector.getCurrentModel().isIncognito()));
+            actions.add(TabSelectionEditorSelectionAction.createAction(
+                    mContext, ShowMode.MENU_ONLY, ButtonType.ICON_AND_TEXT, IconPosition.END));
             actions.add(TabSelectionEditorCloseAction.createAction(
                     mContext, ShowMode.MENU_ONLY, ButtonType.ICON_AND_TEXT, IconPosition.START));
             actions.add(TabSelectionEditorUngroupAction.createAction(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorAction.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorAction.java
index 9d20979f..9189e22 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorAction.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorAction.java
@@ -159,13 +159,10 @@
                                 ColorStateList.valueOf(Color.TRANSPARENT))
                         .with(TabSelectionEditorActionProperties.ICON_TINT,
                                 ColorStateList.valueOf(Color.TRANSPARENT))
-                        .with(TabSelectionEditorActionProperties.SKIP_ICON_TINT, false)
                         .with(TabSelectionEditorActionProperties.ON_CLICK_LISTENER, this::perform)
                         .with(TabSelectionEditorActionProperties.SHOULD_DISMISS_MENU, true)
                         .with(TabSelectionEditorActionProperties.ON_SELECTION_STATE_CHANGE,
                                 this::onSelectionStateChange)
-                        .with(TabSelectionEditorActionProperties.ON_SHOWN_IN_MENU,
-                                this::onShownInMenu)
                         .build();
 
         if (contentDescriptionResourceId == null) return;
@@ -199,8 +196,6 @@
         return true;
     }
 
-    public void onShownInMenu() {}
-
     /**
      * @return Whether the TabSelectionEditor supports applying the actions to related tabs.
      */
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorActionProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorActionProperties.java
index b448425..cd7d144 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorActionProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorActionProperties.java
@@ -41,38 +41,29 @@
             new WritableObjectPropertyKey<>();
 
     /**
-     * Tint for the icon. This should be null if {@code SKIP_ICON_TINT} is true.
+     * Tint for the icon.
      */
     public static final WritableObjectPropertyKey<ColorStateList> ICON_TINT =
             new WritableObjectPropertyKey<>();
 
-    /**
-     * If true skip usage of the {@code ICON_TINT} property. Used if the icon tint is handled
-     * directly by the {@link TabSelectionEditorAction}.
-     */
-    public static final WritableBooleanPropertyKey SKIP_ICON_TINT =
-            new WritableBooleanPropertyKey();
-
     public static final WritableObjectPropertyKey<Runnable> ON_CLICK_LISTENER =
             new WritableObjectPropertyKey<>();
     public static final WritableBooleanPropertyKey SHOULD_DISMISS_MENU =
             new WritableBooleanPropertyKey();
     public static final WritableObjectPropertyKey<Callback<List<Integer>>>
             ON_SELECTION_STATE_CHANGE = new WritableObjectPropertyKey<>();
-    public static final WritableObjectPropertyKey<Runnable> ON_SHOWN_IN_MENU =
-            new WritableObjectPropertyKey<>();
 
     /**
      * Keys for the {@link TabSelectionEditorAction}.
      */
     public static final PropertyKey[] ACTION_KEYS = {MENU_ITEM_ID, SHOW_MODE, BUTTON_TYPE,
             ICON_POSITION, TITLE_RESOURCE_ID, TITLE_IS_PLURAL, CONTENT_DESCRIPTION_RESOURCE_ID,
-            ICON, ENABLED, ITEM_COUNT, TEXT_TINT, ICON_TINT, SKIP_ICON_TINT, ON_CLICK_LISTENER,
-            SHOULD_DISMISS_MENU, ON_SELECTION_STATE_CHANGE, ON_SHOWN_IN_MENU};
+            ICON, ENABLED, ITEM_COUNT, TEXT_TINT, ICON_TINT, ON_CLICK_LISTENER, SHOULD_DISMISS_MENU,
+            ON_SELECTION_STATE_CHANGE};
 
     /**
      * Keys for the {@link TabSelectionEditorMenuItem}.
      */
-    public static final PropertyKey[] MENU_ITEM_KEYS = {MENU_ITEM_ID, TITLE, CONTENT_DESCRIPTION,
-            ICON, ICON_TINT, ENABLED, ITEM_COUNT, ON_SHOWN_IN_MENU};
+    public static final PropertyKey[] MENU_ITEM_KEYS = {
+            MENU_ITEM_ID, TITLE, CONTENT_DESCRIPTION, ICON, ICON_TINT, ENABLED, ITEM_COUNT};
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorActionViewLayout.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorActionViewLayout.java
index e331abb..acfb435 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorActionViewLayout.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorActionViewLayout.java
@@ -80,12 +80,9 @@
     }
 
     /**
-     * @param popupListener for handling show events.
      * @param delegate for handling menu button presses.
      */
-    public void setListMenuButtonDelegate(
-            ListMenuButton.PopupMenuShownListener popupListener, ListMenuButtonDelegate delegate) {
-        mMenuButton.addPopupListener(popupListener);
+    public void setListMenuButtonDelegate(ListMenuButtonDelegate delegate) {
         mMenuButton.setDelegate(delegate);
     }
 
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMediator.java
index 17be223..3a5815fb 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMediator.java
@@ -183,10 +183,7 @@
         if (mActionListModel == null) return;
 
         for (PropertyModel model : mActionListModel) {
-            // TODO(ckitagawa): update these tints with input from UX.
             model.set(TabSelectionEditorActionProperties.TEXT_TINT, toolbarTintColorList);
-            if (model.get(TabSelectionEditorActionProperties.SKIP_ICON_TINT)) continue;
-
             model.set(TabSelectionEditorActionProperties.ICON_TINT, toolbarTintColorList);
         }
     }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenu.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenu.java
index 7ae2503..b4915d03 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenu.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenu.java
@@ -16,7 +16,6 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabSelectionEditorActionViewLayout.ActionViewLayoutDelegate;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
-import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
 import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate;
 import org.chromium.ui.modelutil.LayoutViewBuilder;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
@@ -36,9 +35,9 @@
  * {@link TabSelectionEditorActionViewLayout} for Action views. The menu contains a list of
  * {@link TabSelectionEditorMenuItem}s which hold optional action views if room is available.
  */
-public class TabSelectionEditorMenu
-        implements ListMenu, OnItemClickListener, SelectionDelegate.SelectionObserver<Integer>,
-                   ActionViewLayoutDelegate, ListMenuButton.PopupMenuShownListener {
+public class TabSelectionEditorMenu implements ListMenu, OnItemClickListener,
+                                               SelectionDelegate.SelectionObserver<Integer>,
+                                               ActionViewLayoutDelegate {
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({ListItemType.MENU_ITEM})
     public static @interface ListItemType {
@@ -85,7 +84,7 @@
         mListView.setDivider(null);
         mListView.setOnItemClickListener(this);
 
-        mActionViewLayout.setListMenuButtonDelegate(this, () -> this);
+        mActionViewLayout.setListMenuButtonDelegate(() -> this);
     }
 
     private void registerItemTypes() {
@@ -96,13 +95,6 @@
         // clang-format on
     }
 
-    @Override
-    public void onPopupMenuShown() {
-        for (ListItem listItem : mModelList) {
-            listItem.model.get(TabSelectionEditorActionProperties.ON_SHOWN_IN_MENU).run();
-        }
-    }
-
     private ListItem buildListItem(int menuItemId) {
         // Model values are populated while configuring the TabSelectionEditorMenuItem.
         return new ListItem(ListItemType.MENU_ITEM,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuAdapter.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuAdapter.java
index a9c5ac19d..57baf1402 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuAdapter.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuAdapter.java
@@ -109,9 +109,6 @@
         } else if (key == TabSelectionEditorActionProperties.ON_SELECTION_STATE_CHANGE) {
             menuItem.setOnSelectionStateChange(
                     actionModel.get(TabSelectionEditorActionProperties.ON_SELECTION_STATE_CHANGE));
-        } else if (key == TabSelectionEditorActionProperties.ON_SHOWN_IN_MENU) {
-            menuItem.setOnShownInMenu(
-                    actionModel.get(TabSelectionEditorActionProperties.ON_SHOWN_IN_MENU));
         }
     }
 
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuItem.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuItem.java
index f8bfaa5..84eedd3 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuItem.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuItem.java
@@ -154,15 +154,6 @@
     }
 
     public void setIconTint(@Nullable ColorStateList colorStateList) {
-        // A null colorStateList is used with TabSelectionEditorActionProperties.SKIP_ICON_TINT
-        // = true to signal that a custom tint is used. Ignore null so that this custom tint is
-        // not overridden.
-        if (colorStateList == null) {
-            mIconTint = null;
-            mListItem.model.set(TabSelectionEditorActionProperties.ICON_TINT, null);
-            return;
-        }
-
         // mListItem uses the default icon tint whenever shown. Cache the tint to restore it when
         // the action view shown state is toggled.
         mListItem.model.set(TabSelectionEditorActionProperties.ICON_TINT,
@@ -201,10 +192,6 @@
         mOnSelectionStateChange = callback;
     }
 
-    public void setOnShownInMenu(Runnable runnable) {
-        mListItem.model.set(TabSelectionEditorActionProperties.ON_SHOWN_IN_MENU, runnable);
-    }
-
     /**
      * Handler for click events on the menu item or action view.
      */
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorSelectionAction.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorSelectionAction.java
index 5a245a9..5bf36a2 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorSelectionAction.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorSelectionAction.java
@@ -5,15 +5,11 @@
 package org.chromium.chrome.browser.tasks.tab_management;
 
 import android.content.Context;
-import android.graphics.Color;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.LayerDrawable;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
-import androidx.core.content.res.ResourcesCompat;
-import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
+import androidx.appcompat.content.res.AppCompatResources;
 
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.tab.Tab;
@@ -27,11 +23,10 @@
  * Select all and deselect all toggle action for the {@link TabSelectionEditorMenu}.
  */
 public class TabSelectionEditorSelectionAction extends TabSelectionEditorAction {
-    private static final int BACKGROUND = 0;
-    private static final int CHECKMARK = 1;
-
     private Context mContext;
     private @ActionState int mActionState;
+    private final Drawable mSelectAllIcon;
+    private final Drawable mDeselectAllIcon;
 
     @IntDef({ActionState.UNKNOWN, ActionState.SELECT_ALL, ActionState.DESELECT_ALL})
     @Retention(RetentionPolicy.SOURCE)
@@ -50,42 +45,28 @@
      * @param isIncognito whether the current tab model is incognito this will update dynamically.
      */
     public static TabSelectionEditorAction createAction(Context context, @ShowMode int showMode,
-            @ButtonType int buttonType, @IconPosition int iconPosition, boolean isIncognito) {
+            @ButtonType int buttonType, @IconPosition int iconPosition) {
+        Drawable selectAllIcon =
+                AppCompatResources.getDrawable(context, R.drawable.ic_select_all_24dp);
+        Drawable deselectAllIcon =
+                AppCompatResources.getDrawable(context, R.drawable.ic_deselect_all_24dp);
         return new TabSelectionEditorSelectionAction(
-                context, showMode, buttonType, iconPosition, isIncognito, buildDrawable(context));
+                context, showMode, buttonType, iconPosition, selectAllIcon, deselectAllIcon);
     }
 
     @VisibleForTesting
     TabSelectionEditorSelectionAction(Context context, @ShowMode int showMode,
-            @ButtonType int buttonType, @IconPosition int iconPosition, boolean isIncognito,
-            Drawable drawable) {
+            @ButtonType int buttonType, @IconPosition int iconPosition, Drawable selectAllIcon,
+            Drawable deselectAllIcon) {
         super(R.id.tab_selection_editor_selection_menu_item, showMode, buttonType, iconPosition,
-                R.string.tab_selection_editor_select_all, null, drawable);
+                R.string.tab_selection_editor_select_all, null, selectAllIcon);
 
         mContext = context;
         mActionState = ActionState.UNKNOWN;
-        getPropertyModel().set(TabSelectionEditorActionProperties.ICON_TINT, null);
-        getPropertyModel().set(TabSelectionEditorActionProperties.SKIP_ICON_TINT, true);
+        mSelectAllIcon = selectAllIcon;
+        mDeselectAllIcon = deselectAllIcon;
         getPropertyModel().set(TabSelectionEditorActionProperties.SHOULD_DISMISS_MENU, false);
-        updateState(ActionState.SELECT_ALL, isIncognito);
-        LayerDrawable layers =
-                (LayerDrawable) getPropertyModel().get(TabSelectionEditorActionProperties.ICON);
-        layers.setCallback(new Drawable.Callback() {
-            @Override
-            public void invalidateDrawable(Drawable who) {
-                // No-op.
-            }
-
-            @Override
-            public void scheduleDrawable(Drawable who, Runnable what, long when) {
-                who.invalidateSelf();
-            }
-
-            @Override
-            public void unscheduleDrawable(Drawable who, Runnable what) {
-                who.unscheduleSelf(what);
-            }
-        });
+        updateState(ActionState.SELECT_ALL);
     }
 
     @Override
@@ -94,16 +75,10 @@
     }
 
     @Override
-    public void onShownInMenu() {
-        updateDrawable();
-    }
-
-    @Override
     public void onSelectionStateChange(List<Integer> tabIds) {
         setEnabledAndItemCount(true, tabIds.size());
         updateState(getActionDelegate().areAllTabsSelected() ? ActionState.DESELECT_ALL
-                                                             : ActionState.SELECT_ALL,
-                getTabModelSelector().getCurrentModel().isIncognito());
+                                                             : ActionState.SELECT_ALL);
     }
 
     @Override
@@ -125,64 +100,21 @@
         return false;
     }
 
-    private void updateState(@ActionState int selectionState, boolean isIncognito) {
+    private void updateState(@ActionState int selectionState) {
         if (mActionState == selectionState) return;
 
         mActionState = selectionState;
-        LayerDrawable layers =
-                (LayerDrawable) getPropertyModel().get(TabSelectionEditorActionProperties.ICON);
 
         if (mActionState == ActionState.SELECT_ALL) {
             getPropertyModel().set(TabSelectionEditorActionProperties.TITLE_RESOURCE_ID,
                     R.string.tab_selection_editor_select_all);
-            updateDrawable();
+            getPropertyModel().set(TabSelectionEditorActionProperties.ICON, mSelectAllIcon);
         } else if (mActionState == ActionState.DESELECT_ALL) {
             getPropertyModel().set(TabSelectionEditorActionProperties.TITLE_RESOURCE_ID,
                     R.string.tab_selection_editor_deselect_all);
-            updateDrawable();
+            getPropertyModel().set(TabSelectionEditorActionProperties.ICON, mDeselectAllIcon);
         } else {
             assert false : "Invalid selection state";
         }
     }
-
-    private void updateDrawable() {
-        LayerDrawable layers =
-                (LayerDrawable) getPropertyModel().get(TabSelectionEditorActionProperties.ICON);
-        if (mActionState == ActionState.SELECT_ALL) {
-            layers.getDrawable(BACKGROUND)
-                    .setLevel(
-                            mContext.getResources().getInteger(R.integer.list_item_level_default));
-
-            layers.getDrawable(CHECKMARK).setAlpha(0);
-            layers.getDrawable(CHECKMARK).setTint(Color.TRANSPARENT);
-            layers.invalidateSelf();
-        } else if (mActionState == ActionState.DESELECT_ALL) {
-            layers.getDrawable(BACKGROUND)
-                    .setLevel(
-                            mContext.getResources().getInteger(R.integer.list_item_level_selected));
-
-            layers.getDrawable(CHECKMARK).setAlpha(255);
-            layers.getDrawable(CHECKMARK).setTint(
-                    TabUiThemeProvider.getSelectionActionIconCheckedDrawableColor(mContext));
-            layers.invalidateSelf();
-            ((AnimatedVectorDrawableCompat) layers.getDrawable(CHECKMARK)).start();
-        } else {
-            assert false : "Invalid selection state";
-        }
-    }
-
-    private static Drawable buildDrawable(Context context) {
-        Drawable[] drawables = new Drawable[2];
-
-        Drawable selectionListIcon = ResourcesCompat.getDrawable(context.getResources(),
-                R.drawable.tab_grid_selection_list_icon, context.getTheme());
-        drawables[BACKGROUND] = new InsetDrawable(selectionListIcon,
-                (int) context.getResources().getDimension(
-                        R.dimen.tab_selection_editor_selection_action_inset));
-        drawables[BACKGROUND].setTint(
-                TabUiThemeProvider.getSelectionActionIconBackgroundColor(context));
-        drawables[CHECKMARK] = AnimatedVectorDrawableCompat.create(
-                context, R.drawable.ic_check_googblue_20dp_animated);
-        return new LayerDrawable(drawables);
-    }
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
index 1d03626..30261d2 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -499,9 +499,8 @@
 
         if (mTabSelectionEditorActions == null) {
             mTabSelectionEditorActions = new ArrayList<>();
-            mTabSelectionEditorActions.add(TabSelectionEditorSelectionAction.createAction(mActivity,
-                    ShowMode.MENU_ONLY, ButtonType.ICON_AND_TEXT, IconPosition.END,
-                    mTabModelSelector.getCurrentModel().isIncognito()));
+            mTabSelectionEditorActions.add(TabSelectionEditorSelectionAction.createAction(
+                    mActivity, ShowMode.MENU_ONLY, ButtonType.ICON_AND_TEXT, IconPosition.END));
             mTabSelectionEditorActions.add(TabSelectionEditorCloseAction.createAction(
                     mActivity, ShowMode.MENU_ONLY, ButtonType.ICON_AND_TEXT, IconPosition.START));
             mTabSelectionEditorActions.add(TabSelectionEditorGroupAction.createAction(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
index e0ec536..6b60a8e 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
@@ -187,28 +187,6 @@
     }
 
     /**
-     * Returns the {@link ColorInt} to use for the {@link TabSelectionEditorSelectionAction}
-     * icon background.
-     *
-     * @param context {@link Context} used to retrieve color.
-     * @return The {@link ColorInt} for select all icon background.
-     */
-    public static @ColorInt int getSelectionActionIconBackgroundColor(Context context) {
-        return MaterialColors.getColor(context, R.attr.colorOnSurfaceVariant, TAG);
-    }
-
-    /**
-     * Returns the {@link ColorInt} to use for the "check" drawable on the
-     * {@link TabSelectionEditorSelectionAction}.
-     *
-     * @param context {@link Context} used to retrieve color.
-     * @return The {@link ColorInt} for "check" drawable.
-     */
-    public static @ColorInt int getSelectionActionIconCheckedDrawableColor(Context context) {
-        return MaterialColors.getColor(context, org.chromium.chrome.R.attr.colorOnPrimary, TAG);
-    }
-
-    /**
      * Returns the thumbnail placeholder color resource id based on the incognito mode.
      *
      * @param isIncognito Whether the color is used for incognito mode.
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuTest.java
index 14115fa4..b65d1c0 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorMenuTest.java
@@ -102,8 +102,8 @@
     public RenderTestRule mRenderTestRule =
             RenderTestRule.Builder.withPublicCorpus()
                     .setBugComponent(Component.UI_BROWSER_MOBILE_TAB_SWITCHER_GRID)
-                    .setRevision(3)
-                    .setDescription("Pluralize strings")
+                    .setRevision(4)
+                    .setDescription("New selection icons")
                     .build();
 
     @Rule
@@ -321,8 +321,8 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             actions.add(new FakeTabSelectionEditorAction(getActivity(),
                     R.id.tab_selection_editor_close_menu_item, ShowMode.IF_ROOM, ButtonType.TEXT,
-                    IconPosition.END, R.plurals.tab_selection_editor_close_tabs,
-                    R.drawable.ic_close_tabs_24dp));
+                    IconPosition.END, R.string.tab_selection_editor_select_all,
+                    R.drawable.ic_select_all_24dp));
             configureMenuWithActions(actions);
         });
 
@@ -359,8 +359,8 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             actions.add(new FakeTabSelectionEditorAction(getActivity(),
                     R.id.tab_selection_editor_close_menu_item, ShowMode.MENU_ONLY, ButtonType.TEXT,
-                    IconPosition.START, R.plurals.tab_selection_editor_close_tabs,
-                    R.drawable.ic_close_tabs_24dp));
+                    IconPosition.START, R.string.tab_selection_editor_deselect_all,
+                    R.drawable.ic_deselect_all_24dp));
             configureMenuWithActions(actions);
         });
 
@@ -370,7 +370,7 @@
 
         PopupListener listener = new PopupListener();
         openMenu(listener);
-        assertMenuItem("Close tabs", false);
+        assertMenuItem("Deselect all", false);
 
         forceFinishRollAnimation();
         mRenderTestRule.render(
@@ -626,8 +626,10 @@
     }
 
     private void setSelectedItems(Set<Integer> tabIds) {
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> { mSelectionDelegate.setSelectedItems(tabIds); });
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mSelectionDelegate.setSelectedItems(tabIds);
+            mToolbar.invalidate();
+        });
     }
 
     private void forceFinishRollAnimation() {
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
index 8173d39..400dccf 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
@@ -136,8 +136,8 @@
     public ChromeRenderTestRule mRenderTestRule =
             ChromeRenderTestRule.Builder.withPublicCorpus()
                     .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_MOBILE_TAB_SWITCHER)
-                    .setRevision(4)
-                    .setDescription("TabSelectionEditorV2 UI Polish")
+                    .setRevision(5)
+                    .setDescription("TabSelectionEditorV2 New selection icons")
                     .build();
 
     @Mock
@@ -874,9 +874,9 @@
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             List<TabSelectionEditorAction> actions = new ArrayList<>();
-            actions.add(TabSelectionEditorSelectionAction.createAction(
-                    sActivityTestRule.getActivity(), ShowMode.IF_ROOM, ButtonType.ICON_AND_TEXT,
-                    IconPosition.END, /*isIncognito=*/false));
+            actions.add(
+                    TabSelectionEditorSelectionAction.createAction(sActivityTestRule.getActivity(),
+                            ShowMode.IF_ROOM, ButtonType.ICON_AND_TEXT, IconPosition.END));
 
             mTabSelectionEditorController.configureToolbarWithMenuItems(actions, null);
         });
@@ -1081,9 +1081,9 @@
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             List<TabSelectionEditorAction> actions = new ArrayList<>();
-            actions.add(TabSelectionEditorSelectionAction.createAction(
-                    sActivityTestRule.getActivity(), ShowMode.IF_ROOM, ButtonType.ICON_AND_TEXT,
-                    IconPosition.END, /*isIncognito=*/false));
+            actions.add(
+                    TabSelectionEditorSelectionAction.createAction(sActivityTestRule.getActivity(),
+                            ShowMode.IF_ROOM, ButtonType.ICON_AND_TEXT, IconPosition.END));
 
             mTabSelectionEditorController.configureToolbarWithMenuItems(actions, null);
         });
@@ -1242,9 +1242,9 @@
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             List<TabSelectionEditorAction> actions = new ArrayList<>();
-            actions.add(TabSelectionEditorSelectionAction.createAction(
-                    sActivityTestRule.getActivity(), ShowMode.MENU_ONLY, ButtonType.TEXT,
-                    IconPosition.START, /*isIncognito=*/false));
+            actions.add(
+                    TabSelectionEditorSelectionAction.createAction(sActivityTestRule.getActivity(),
+                            ShowMode.MENU_ONLY, ButtonType.TEXT, IconPosition.START));
             actions.add(TabSelectionEditorCloseAction.createAction(sActivityTestRule.getActivity(),
                     ShowMode.MENU_ONLY, ButtonType.TEXT, IconPosition.START));
 
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorSelectionActionUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorSelectionActionUnitTest.java
index 9686777..22cfa19d 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorSelectionActionUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorSelectionActionUnitTest.java
@@ -10,6 +10,7 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 
 import androidx.test.filters.SmallTest;
 
@@ -56,10 +57,9 @@
         MockitoAnnotations.initMocks(this);
         mContext = Robolectric.buildActivity(Activity.class).get();
         mContext.setTheme(org.chromium.chrome.tab_ui.R.style.Theme_BrowserUI_DayNight);
-        boolean isIncognito = false;
-        mAction = TabSelectionEditorSelectionAction.createAction(mContext, ShowMode.IF_ROOM,
-                ButtonType.ICON_AND_TEXT, IconPosition.END, isIncognito);
-        mTabModel = spy(new MockTabModel(isIncognito, null));
+        mAction = TabSelectionEditorSelectionAction.createAction(
+                mContext, ShowMode.IF_ROOM, ButtonType.ICON_AND_TEXT, IconPosition.END);
+        mTabModel = spy(new MockTabModel(false, null));
         when(mTabModelSelector.getCurrentModel()).thenReturn(mTabModel);
         // TODO(ckitagawa): Add tests for when this is true.
         mAction.configure(mTabModelSelector, mSelectionDelegate, mDelegate, false);
@@ -80,10 +80,8 @@
                         TabSelectionEditorActionProperties.CONTENT_DESCRIPTION_RESOURCE_ID));
         Assert.assertNotNull(
                 mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ICON));
-        Assert.assertNull(
+        Assert.assertNotNull(
                 mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ICON_TINT));
-        Assert.assertTrue(
-                mAction.getPropertyModel().get(TabSelectionEditorActionProperties.SKIP_ICON_TINT));
     }
 
     @Test
@@ -102,6 +100,10 @@
                 true, mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ENABLED));
         Assert.assertEquals(
                 0, mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ITEM_COUNT));
+        Assert.assertNotNull(
+                mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ICON));
+        Drawable selectAllIcon =
+                mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ICON);
 
         // 1 tab of 2 selected.
         selectedTabIds.add(0);
@@ -113,6 +115,8 @@
                 true, mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ENABLED));
         Assert.assertEquals(
                 1, mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ITEM_COUNT));
+        Assert.assertEquals(selectAllIcon,
+                mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ICON));
 
         // 2 tabs of 2 selected.
         selectedTabIds.add(1);
@@ -125,6 +129,8 @@
                 true, mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ENABLED));
         Assert.assertEquals(
                 2, mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ITEM_COUNT));
+        Assert.assertNotEquals(selectAllIcon,
+                mAction.getPropertyModel().get(TabSelectionEditorActionProperties.ICON));
     }
 
     @Test
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
index a977fef..d2c90ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
@@ -244,15 +244,6 @@
                 && !ChromeFeatureList.sElasticOverscroll.isEnabled()) {
             setTheme(R.style.ThemeOverlay_DisableOverscroll);
         }
-
-        // TODO(https://crbug.com/1345778): Remove these overlays.
-        // We apply an extra theme overlay to override some of the dynamic colors. For example,
-        // android:textColorHighlight is overridden by dynamic colors, preventing us from specifying
-        // the alpha for the selected text highlight. In this case, the overridden colors should
-        // still use dynamic colors, as in the android:textColorHighlight example where we use a
-        // color state list that depends on colorPrimary.
-        setTheme(R.style.ThemeOverlay_DynamicColorOverrides);
-        setTheme(R.style.ThemeOverlay_DynamicButtons);
     }
 
     /**
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 f207a3ed..d05eba1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java
@@ -11,11 +11,8 @@
 
 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;
 
@@ -27,9 +24,6 @@
  */
 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;
 
     /**
@@ -60,20 +54,6 @@
                         && 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)
@@ -109,4 +89,13 @@
     public @Px int calculateSoftKeyboardHeight(View rootView) {
         return calculateKeyboardHeight(rootView);
     }
-}
\ No newline at end of file
+
+    @Override
+    public int calculateTotalKeyboardHeight(View rootView) {
+        int accessoryHeight = 0;
+        if (mManualFillingComponentSupplier.hasValue()) {
+            accessoryHeight = mManualFillingComponentSupplier.get().getKeyboardExtensionHeight();
+        }
+        return calculateKeyboardHeight(rootView) + accessoryHeight;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
index 8d6dcd6..498d540 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
@@ -379,6 +379,14 @@
     }
 
     @Override
+    public int getVirtualKeyboardHeight() {
+        if (mActivity == null) return 0;
+
+        View rootView = mActivity.getWindow().getDecorView().getRootView();
+        return mTab.getWindowAndroid().getKeyboardDelegate().calculateTotalKeyboardHeight(rootView);
+    }
+
+    @Override
     public void enterFullscreenModeForTab(boolean prefersNavigationBar, boolean prefersStatusBar) {
         if (mFullscreenManager != null) {
             mFullscreenManager.onEnterFullscreen(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
index d67ea1c..7a67546 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
@@ -54,12 +54,6 @@
         super(nativeBookmarkBridge);
     }
 
-    @Override
-    // TODO(crbug.com/1150129): Remove this method once destroy calls are removed.
-    public void destroy() {
-        super.destroy();
-    }
-
     /**
      * Add an observer that listens to delete events that go through the bookmark model.
      * @param observer The observer to add.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java
index b2d47fd..4328b8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.bookmarks;
 
 import android.content.Context;
+import android.os.Build;
 import android.widget.CompoundButton;
 
 import androidx.annotation.Nullable;
@@ -17,6 +18,7 @@
 import org.chromium.chrome.browser.bookmarks.PowerBookmarkMetrics.PriceTrackingState;
 import org.chromium.chrome.browser.commerce.PriceTrackingUtils;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
+import org.chromium.chrome.browser.price_tracking.PriceDropNotificationManagerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.subscriptions.CommerceSubscription;
 import org.chromium.chrome.browser.subscriptions.SubscriptionsManager;
@@ -157,6 +159,12 @@
                     });
         }
 
+        // Make sure the notification channel is initialized when the user tracks a product.
+        // TODO(crbug.com/1382191): Add a SubscriptionsObserver in the PriceDropNotificationManager
+        // and initialize the channel there.
+        if (toggled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            PriceDropNotificationManagerFactory.create().createNotificationChannel();
+        }
         setPriceTrackingIconForEnabledState(toggled);
         PriceTrackingUtils.setPriceTrackingStateForBookmark(Profile.getLastUsedRegularProfile(),
                 mBookmarkId.getId(), toggled, mSubscriptionsManagerCallback);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java
index a461428..bb6bff6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.bookmarks;
 
 import android.content.res.Resources;
+import android.os.Build;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
@@ -18,6 +19,7 @@
 import org.chromium.chrome.browser.commerce.PriceTrackingUtils;
 import org.chromium.chrome.browser.commerce.ShoppingServiceFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.price_tracking.PriceDropNotificationManagerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.subscriptions.CommerceSubscription;
 import org.chromium.chrome.browser.subscriptions.CommerceSubscription.CommerceSubscriptionType;
@@ -168,6 +170,12 @@
             snackbarManager.showSnackbar(snackbar);
             callback.onResult(success);
         };
+        // Make sure the notification channel is initialized when the user tracks a product.
+        // TODO(crbug.com/1382191): Add a SubscriptionsObserver in the PriceDropNotificationManager
+        // and initialize the channel there.
+        if (enabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            PriceDropNotificationManagerFactory.create().createNotificationChannel();
+        }
         PriceTrackingUtils.setPriceTrackingStateForBookmark(
                 Profile.getLastUsedRegularProfile(), bookmarkId.getId(), enabled, wrapperCallback);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
index 61f29aa..05561af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -39,6 +39,8 @@
 import org.chromium.chrome.browser.customtabs.FirstMeaningfulPaintObserver;
 import org.chromium.chrome.browser.customtabs.PageLoadMetricsObserver;
 import org.chromium.chrome.browser.customtabs.ReparentingTaskProvider;
+import org.chromium.chrome.browser.customtabs.features.TabInteractionRecorder;
+import org.chromium.chrome.browser.customtabs.features.sessionrestore.SessionRestoreManager;
 import org.chromium.chrome.browser.customtabs.features.sessionrestore.SessionRestoreMessageController;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -196,7 +198,10 @@
      */
     public void closeTab() {
         TabModel model = mTabFactory.getTabModelSelector().getCurrentModel();
-        model.closeTab(mTabProvider.getTab(), false, false, false);
+        Tab currentTab = mTabProvider.getTab();
+        if (!maybeStoreTab(currentTab)) {
+            model.closeTab(currentTab, false, false, false);
+        }
     }
 
     public boolean onlyOneTabRemaining() {
@@ -205,6 +210,12 @@
     }
 
     public void closeAndForgetTab() {
+        // TODO(https://crbug.com/1379452): Store all the tabs in the tab model.
+        if (mTabFactory.getTabModelSelector().getCurrentModel().getCount() > 0) {
+            // Ignore the results, as we are closing all the tabs regardless at the end.
+            maybeStoreTab(mTabProvider.getTab());
+        }
+
         mTabFactory.getTabModelSelector().closeAllTabs(true);
         mTabPersistencePolicy.deleteMetadataStateFileAsync();
     }
@@ -485,4 +496,27 @@
 
         tab.addObserver(mediaObserver);
     }
+
+    /**
+     * Store the tab into {@link SessionRestoreManager}.
+     * @param tab The tab to be stored.
+     * @return Whether storing tab succeeded.
+     */
+    private boolean maybeStoreTab(@Nullable Tab tab) {
+        if (tab == null || mConnection.getSessionRestoreManager() == null) return false;
+
+        SessionRestoreManager sessionRestoreManager = mConnection.getSessionRestoreManager();
+        TabInteractionRecorder recorder = TabInteractionRecorder.getFromTab(tab);
+        if (recorder == null || !recorder.hadInteraction()) {
+            return false;
+        }
+
+        // TODO(wenyufu): Add observer to record metrics for tab eviction.
+        boolean success = sessionRestoreManager.store(tab);
+        if (!success) {
+            return false;
+        }
+        mTabProvider.removeTab();
+        return true;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorder.java
index 83cf25b11..c8afc28 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorder.java
@@ -81,8 +81,7 @@
      */
     public void onTabClosing() {
         long timestamp = SystemClock.uptimeMillis();
-        boolean hadInteraction =
-                TabInteractionRecorderJni.get().hadInteraction(mNativeTabInteractionRecorder);
+        boolean hadInteraction = hadInteraction();
 
         Log.d(TAG,
                 String.format(Locale.US,
@@ -97,6 +96,22 @@
     }
 
     /**
+     * Whether this instance has seen interactions in associated tab. Different than
+     * {@link #didGetUserInteraction()}, this function returns whether user had interactions with
+     * form entries, or had navigation entries by the time this method is called.
+     *
+     * More details see chrome/browser/android/customtabs/tab_interaction_recorder_android.h
+     */
+    public boolean hadInteraction() {
+        return TabInteractionRecorderJni.get().hadInteraction(mNativeTabInteractionRecorder);
+    }
+
+    /** Reset the interaction recorded. */
+    public void reset() {
+        TabInteractionRecorderJni.get().reset(mNativeTabInteractionRecorder);
+    }
+
+    /**
      * Whether there has been direct user interaction with the WebContents in the tab.
      * For more detail see content/public/browser/web_contents_observer.h
      *
@@ -127,5 +142,6 @@
         TabInteractionRecorder createForTab(Tab tab);
         boolean didGetUserInteraction(long nativeTabInteractionRecorderAndroid);
         boolean hadInteraction(long nativeTabInteractionRecorderAndroid);
+        void reset(long nativeTabInteractionRecorderAndroid);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManager.java
index 928c0932..ebbd037 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManager.java
@@ -44,6 +44,11 @@
      */
     void setEvictionTimeout(long timeoutMs);
 
+    /**
+     * Cancel the eviction timeout started during {@link #store}.
+     */
+    void cancelEvictionTimer();
+
     /** Clean the stored tab, if any. */
     void clearCache();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerImpl.java
index 39b13eaf..2b1c2651 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerImpl.java
@@ -4,39 +4,156 @@
 
 package org.chromium.chrome.browser.customtabs.features.sessionrestore;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.CallbackController;
+import org.chromium.base.ObserverList;
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskTraits;
+import org.chromium.chrome.browser.app.tab_activity_glue.ReparentingTask;
+import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton;
+import org.chromium.chrome.browser.customtabs.features.TabInteractionRecorder;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.AsyncTabParams;
+import org.chromium.chrome.browser.tabmodel.TabReparentingParams;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.TimeUnit;
 
 /**
- * Default implementation for SessionRestoreManager.
+ * Main coordinator for SessionRestoreManager. This class take charge in putting tab into, and take
+ * out from {@link TabFreezer}, which dedicate to putting tab into freezing / unfrozen mode.
+ *
+ * This class handles:
+ * - Handle eviction timeout
+ * - Manage TabInteractionRecorder states when store / restore
+ * - Open for observers and dispatch events
  */
 public class SessionRestoreManagerImpl implements SessionRestoreManager {
+    private static final long DEFAULT_EVICTION_TIMEOUT = TimeUnit.MINUTES.toMillis(5);
+
+    // TODO(wenyufu): Add histogram for cache being cleaned and make these @IntDef
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({EvictionReason.CLIENT_CLEAN, EvictionReason.TIMEOUT, EvictionReason.NEW_TAB_OVERRIDE})
+    @interface EvictionReason {
+        int CLIENT_CLEAN = 0;
+        int TIMEOUT = 1;
+        int NEW_TAB_OVERRIDE = 2;
+    }
+
+    private final TabFreezer mTabFreezer;
+    private final ObserverList<SessionRestoreManager.Observer> mObservers = new ObserverList<>();
+
+    private @Nullable CallbackController mCallbackController;
+
+    private long mEvictionTimeout = DEFAULT_EVICTION_TIMEOUT;
+
+    public SessionRestoreManagerImpl() {
+        this(new TabFreezer());
+    }
+
+    @VisibleForTesting
+    SessionRestoreManagerImpl(TabFreezer testTebFreezer) {
+        mTabFreezer = testTebFreezer;
+    }
+
     @Override
-    public boolean store(Tab tabToRestore) {
-        return false;
+    public boolean store(Tab tabToStore) {
+        if (mTabFreezer.hasTab()) {
+            cancelEvictionTimer();
+            clearCacheWithReason(EvictionReason.NEW_TAB_OVERRIDE);
+        }
+
+        TabInteractionRecorder recorder = TabInteractionRecorder.getFromTab(tabToStore);
+        assert recorder != null : "Tab to store have to has an interaction recorder.";
+
+        // Manually record the interaction related prefs for the storing tab.
+        ReparentingTask.from(tabToStore).detach();
+        recorder.onTabClosing();
+
+        boolean success = mTabFreezer.freeze(tabToStore);
+        if (!success) {
+            return false;
+        }
+
+        if (mEvictionTimeout > 0) {
+            startEvictionTimer();
+        }
+        return true;
     }
 
     @Nullable
     @Override
     public Tab restoreTab() {
-        return null;
+        if (!canRestoreTab()) return null;
+        cancelEvictionTimer();
+        Tab tab = mTabFreezer.unfreeze();
+
+        TabInteractionRecorder recorder = TabInteractionRecorder.getFromTab(tab);
+        assert recorder != null : "Tab to restore has to have an interaction recorder.";
+        recorder.reset();
+
+        return tab;
     }
 
     @Override
     public boolean canRestoreTab() {
-        return false;
+        return mTabFreezer.hasTab();
     }
 
     @Override
-    public void setEvictionTimeout(long timeoutMs) {}
+    public void setEvictionTimeout(long timeoutMs) {
+        mEvictionTimeout = timeoutMs;
+    }
 
     @Override
-    public void clearCache() {}
+    public void cancelEvictionTimer() {
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
+    }
 
     @Override
-    public void addObserver(Observer observer) {}
+    public void clearCache() {
+        if (!mTabFreezer.hasTab()) return;
+        cancelEvictionTimer();
+        clearCacheWithReason(EvictionReason.CLIENT_CLEAN);
+    }
 
     @Override
-    public void removeObserver(Observer observer) {}
+    public void addObserver(Observer observer) {
+        mObservers.addObserver(observer);
+    }
+
+    @Override
+    public void removeObserver(Observer observer) {
+        mObservers.removeObserver(observer);
+    }
+
+    private void startEvictionTimer() {
+        assert mCallbackController == null : "An eviction timer is in place.";
+        mCallbackController = new CallbackController();
+        PostTask.postDelayedTask(TaskTraits.BEST_EFFORT,
+                mCallbackController.makeCancelable(
+                        () -> clearCacheWithReason(EvictionReason.TIMEOUT)),
+                mEvictionTimeout /*ms*/);
+    }
+
+    private void clearCacheWithReason(int reason) {
+        int tabId = mTabFreezer.clear();
+        // TODO(https://crbug.com/1385960): Remove this line if clean up is not required.
+        AsyncTabParams param =
+                AsyncTabParamsManagerSingleton.getInstance().getAsyncTabParams().get(tabId);
+        if (param instanceof TabReparentingParams) {
+            AsyncTabParamsManagerSingleton.getInstance().remove(tabId);
+        }
+
+        for (Observer obs : mObservers) {
+            obs.onCacheCleared(reason);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/TabFreezer.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/TabFreezer.java
new file mode 100644
index 0000000..1e29576
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/TabFreezer.java
@@ -0,0 +1,68 @@
+// 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.features.sessionrestore;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.Log;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabHidingType;
+
+/**
+ * Class used to put tab in freezing state, and remove live references.
+ */
+class TabFreezer {
+    private static final String TAG = "SessionRestore";
+    private @Nullable Tab mTab;
+
+    /**
+     * Freeze a tab and store it.
+     * @param tab Tab to freeze.
+     * @return Whether freezing is success
+     */
+    public boolean freeze(Tab tab) {
+        mTab = tab;
+        try {
+            // TODO(https://crbug.com/1379452): Detach tab with living Java references (e.g.
+            // observers).
+            // TODO(https://crbug.com/1383325): Freeze the web contents when the API is available.
+            mTab.hide(TabHidingType.REPARENTED);
+
+            return true;
+        } catch (Exception e) {
+            Log.e(TAG, "Store freeze with exception: " + e);
+        }
+        return false;
+    }
+
+    /**
+     * Unfreeze the stored tab and pass it.
+     * @return The unfrozen Tab.
+     */
+    public Tab unfreeze() {
+        Tab tab = mTab;
+        mTab = null;
+
+        return tab;
+    }
+
+    /** Return whether a tab is stored in this instance. */
+    public boolean hasTab() {
+        return mTab != null;
+    }
+
+    /**
+     * Destroy the tab if exists in the TabFreezer.
+     * @return the Tab Id of the cleared tab.
+     * */
+    public int clear() {
+        if (!hasTab()) return Tab.INVALID_TAB_ID;
+
+        int tabId = mTab.getId();
+        mTab.destroy();
+        mTab = null;
+        return tabId;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
index e3f204b2..0d7122b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
@@ -390,6 +390,11 @@
         return mDelegate.controlsResizeView();
     }
 
+    @Override
+    public int getVirtualKeyboardHeight() {
+        return mDelegate.getVirtualKeyboardHeight();
+    }
+
     @VisibleForTesting
     void showFramebustBlockInfobarForTesting(String url) {
         TabWebContentsDelegateAndroidImplJni.get().showFramebustBlockInfoBar(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
index 65abd22..31d9fc1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
@@ -82,6 +82,7 @@
     private final @ColorInt int mStandardDefaultThemeColor;
     private final @ColorInt int mIncognitoDefaultThemeColor;
     private final @ColorInt int mActiveOmniboxDefaultColor;
+    private boolean mToolbarColorChanged;
     private @ColorInt int mToolbarColor;
 
     private @Nullable TabModelSelector mTabModelSelector;
@@ -223,6 +224,7 @@
 
         activityLifecycleDispatcher.register(this);
         mTopUiThemeColor = topUiThemeColorProvider;
+        mToolbarColorChanged = false;
     }
 
     // DestroyObserver implementation.
@@ -261,6 +263,9 @@
             return;
         }
 
+        // Set mToolbarColorChanged to true as an extra check to prevent rendering status bar with
+        // default color if toolbar never changes, for example, in dark mode.
+        mToolbarColorChanged = true;
         mToolbarColor = color;
         updateStatusBarColor();
     }
@@ -335,8 +340,8 @@
         // The theme should be restored when Omnibox focus clears.
         if (mIsOmniboxFocused) {
             // If the flag is enabled, we will use the toolbar color.
-            if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor()
-                    && mToolbarAnimationInProgress) {
+            if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor() && mToolbarAnimationInProgress
+                    && mToolbarColorChanged) {
                 return mToolbarColor;
             }
             return calculateDefaultStatusBarColor();
@@ -360,7 +365,8 @@
 
         // Return status bar color to match the toolbar.
         // If the flag is enabled, we will use the toolbar color.
-        if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor() && mToolbarAnimationInProgress) {
+        if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor() && mToolbarAnimationInProgress
+                && mToolbarColorChanged) {
             return mToolbarColor;
         }
         return mTopUiThemeColor.getThemeColorOrFallback(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ViewTransitionPixelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ViewTransitionPixelTest.java
new file mode 100644
index 0000000..2e2ef91
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ViewTransitionPixelTest.java
@@ -0,0 +1,491 @@
+// 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;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.support.test.InstrumentationRegistry;
+import android.text.TextUtils;
+import android.util.Base64;
+
+import androidx.test.filters.MediumTest;
+
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Criteria;
+import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.test.util.Coordinates;
+import org.chromium.content_public.browser.test.util.DOMUtils;
+import org.chromium.content_public.browser.test.util.JavaScriptUtils;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.ui.mojom.VirtualKeyboardMode;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Tests view-transitions API in relation to Android Chrome UI.
+ *
+ * These test that view transitions result in correctly sized and positioned transitions in the
+ * presence/absence of UI such as virtual-keyboard and moveable URL bar.
+ *
+ * See https://github.com/WICG/shared-element-transitions/blob/main/explainer.md
+ * TODO(bokan): Link to relevant spec when ready.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        "enable-features=ViewTransition", "hide-scrollbars"})
+@Batch(Batch.PER_CLASS)
+public class ViewTransitionPixelTest {
+    @Rule
+    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+
+    private static final String TEXTFIELD_DOM_ID = "inputElement";
+    private static final int TEST_TIMEOUT = 10000;
+
+    // How many pixels can differ in the pixel test before comparison is considered non-equivalent.
+    // Experimentally determined to allow some difference due to compositing and raster but not to
+    // allow false positives.
+    private static final int PIXEL_DIFF_FUZZINESS = 4000;
+
+    // When performing the pixel test, this is the threshold within which pixel color channels are
+    // considered equivalent. Experimentally determined to allow minor raster differences when
+    // compositing decisions change.
+    private static final int PIXEL_COLOR_CHANNEL_DIFF_FUZZINESS = 10;
+
+    private static final String CAPTURE_NEW = "new";
+    private static final String CAPTURE_OLD = "old";
+
+    private EmbeddedTestServer mTestServer;
+
+    private int mInitialPageHeight;
+    private double mInitialVVHeight;
+
+    @VirtualKeyboardMode.EnumType
+    private int mVirtualKeyboardMode = VirtualKeyboardMode.RESIZES_VISUAL;
+
+    @Before
+    public void setUp() {
+        mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+    }
+
+    @After
+    public void tearDown() {
+        if (mTestServer != null) {
+            mTestServer.stopAndDestroyServer();
+        }
+    }
+
+    private void startTest(@VirtualKeyboardMode.EnumType int vkMode, String captureWhich)
+            throws Throwable {
+        mVirtualKeyboardMode = vkMode;
+        String url = "/chrome/test/data/android/view_transition.html";
+
+        if (mVirtualKeyboardMode == VirtualKeyboardMode.RESIZES_VISUAL) {
+            url += "?resizes-visual";
+        } else if (mVirtualKeyboardMode == VirtualKeyboardMode.RESIZES_CONTENT) {
+            url += "?resizes-content";
+        } else {
+            Assert.fail("Unexpected virtual keyboard mode");
+        }
+
+        // Set the animation direction to either capture the new or the old state.
+        url += "&" + captureWhich;
+
+        mActivityTestRule.startMainActivityWithURL(mTestServer.getURL(url));
+        mActivityTestRule.waitForActivityNativeInitializationComplete();
+
+        mInitialPageHeight = getPageInnerHeight();
+        mInitialVVHeight = getVisualViewportHeight();
+
+        // startMainActivityWithURL will wait for the renderer to produce a
+        // frame but not for it to be presented. Since we can take screenshots
+        // right after this, ensure we've presented.
+        waitForFramePresented();
+    }
+
+    private void assertWaitForKeyboardStatus(final boolean show) {
+        CriteriaHelper.pollUiThread(() -> {
+            boolean isKeyboardShowing = mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
+                    mActivityTestRule.getActivity(), mActivityTestRule.getActivity().getTabsView());
+            Criteria.checkThat(isKeyboardShowing, Matchers.is(show));
+        }, TEST_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+    }
+
+    private void assertWaitForPageHeight(double expectedPageHeight) {
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            try {
+                int curHeight = getPageInnerHeight();
+                // Allow 1px delta to account for device scale factor rounding.
+                Criteria.checkThat(
+                        (double) curHeight, Matchers.closeTo(expectedPageHeight, /*error=*/1.0));
+            } catch (Throwable e) {
+                throw new CriteriaNotSatisfiedException(e);
+            }
+        }, TEST_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+    }
+
+    private void assertWaitForVisualViewportHeight(double expectedHeight) {
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            try {
+                double curHeight = getVisualViewportHeight();
+                // Allow 1px delta to account for device scale factor rounding.
+                Criteria.checkThat(curHeight, Matchers.closeTo(expectedHeight, /*error=*/1.0));
+            } catch (Throwable e) {
+                throw new CriteriaNotSatisfiedException(e);
+            }
+        }, TEST_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+    }
+
+    private WebContents getWebContents() {
+        return mActivityTestRule.getActivity().getActivityTab().getWebContents();
+    }
+
+    private int getPageInnerHeight() throws Throwable {
+        return Integer.parseInt(JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                getWebContents(), "window.innerHeight"));
+    }
+
+    private double getVisualViewportHeight() throws Throwable {
+        return Float.parseFloat(JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                getWebContents(), "window.visualViewport.height"));
+    }
+
+    private void showAndWaitForKeyboard() throws Throwable {
+        DOMUtils.clickNode(getWebContents(), TEXTFIELD_DOM_ID);
+        TestThreadUtils.runOnUiThreadBlocking(()
+                                                      -> mActivityTestRule.getActivity()
+                                                                 .getManualFillingComponent()
+                                                                 .forceShowForTesting());
+
+        assertWaitForKeyboardStatus(true);
+
+        double keyboardHeight = getKeyboardHeightDp();
+
+        // Use less than or equal since the keyboard may actually include accessories like the
+        // Autofill bar.
+        if (mVirtualKeyboardMode == VirtualKeyboardMode.RESIZES_VISUAL) {
+            assertWaitForVisualViewportHeight(mInitialVVHeight - keyboardHeight);
+        } else if (mVirtualKeyboardMode == VirtualKeyboardMode.RESIZES_CONTENT) {
+            assertWaitForPageHeight(mInitialPageHeight - keyboardHeight);
+        } else {
+            Assert.fail("Unimplemented keyboard mode");
+        }
+    }
+
+    private void hideKeyboard() throws Throwable {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> mActivityTestRule.getActivity().getManualFillingComponent().hide());
+        JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                getWebContents(), "document.activeElement.blur()");
+    }
+
+    private void waitForKeyboardHidden() {
+        assertWaitForKeyboardStatus(false);
+        if (mVirtualKeyboardMode == VirtualKeyboardMode.RESIZES_VISUAL) {
+            assertWaitForVisualViewportHeight(mInitialVVHeight);
+        } else if (mVirtualKeyboardMode == VirtualKeyboardMode.RESIZES_CONTENT) {
+            assertWaitForPageHeight(mInitialPageHeight);
+        } else {
+            Assert.fail("Unimplemented keyboard mode");
+        }
+    }
+
+    private double getKeyboardHeightDp() {
+        final double dpi = Coordinates.createFor(getWebContents()).getDeviceScaleFactor();
+        double keyboardHeightPx =
+                mActivityTestRule.getKeyboardDelegate().calculateTotalKeyboardHeight(
+                        mActivityTestRule.getActivity().getWindow().getDecorView().getRootView());
+        return keyboardHeightPx / dpi;
+    }
+
+    private String bitmapToDataUrl(Bitmap bmp) {
+        // Scale down the image so that we can fit the resulting data: URL into Android's 4000
+        // character log line limit. 300px of width is an arbitrary choice that experimentally
+        // results in data: URLs about 1000 chars in length.
+        double scale = 300.0 / bmp.getWidth();
+        Bitmap scaledDownBmp = Bitmap.createScaledBitmap(
+                bmp, (int) (bmp.getWidth() * scale), (int) (bmp.getHeight() * scale), true);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        scaledDownBmp.compress(Bitmap.CompressFormat.PNG, 50, os);
+        String url =
+                "data:image/png;base64," + Base64.encodeToString(os.toByteArray(), Base64.NO_WRAP);
+
+        if (url.length() > 4000) {
+            return "<IMAGE TOO LARGE TO FIT IN LOG>";
+        }
+
+        return url;
+    }
+
+    private Bitmap takeScreenshot() throws Throwable {
+        Context context = InstrumentationRegistry.getContext();
+
+        final CallbackHelper ch = new CallbackHelper();
+        final AtomicReference<String> screenshotOutputPath = new AtomicReference<>();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            getWebContents().getRenderWidgetHostView().writeContentBitmapToDiskAsync(
+                    /*width=*/0, /*height=*/0, context.getCacheDir().getAbsolutePath(), path -> {
+                        screenshotOutputPath.set(path);
+                        ch.notifyCalled();
+                    });
+        });
+
+        ch.waitForNext(TEST_TIMEOUT, TimeUnit.SECONDS);
+
+        if (TextUtils.isEmpty(screenshotOutputPath.get())) {
+            throw new Exception("Failed to take screenshot");
+        }
+
+        File outputFile = new File(screenshotOutputPath.get());
+        outputFile.deleteOnExit();
+        Bitmap screenshot = BitmapFactory.decodeFile(outputFile.getAbsolutePath());
+        outputFile.delete();
+        return screenshot;
+    }
+
+    // This will start the transition and wait until snapshots for the old page have been
+    // taken. This will return only once the domUpdate callback has run (but not resolved). The
+    // transition animation doesn't start until the test calls startTransitionAnimation.
+    private void createTransitionAndWaitUntilDomUpdateDispatched() throws Throwable {
+        JavaScriptUtils.executeJavaScriptAndWaitForResult(getWebContents(), "createTransition()");
+        JavaScriptUtils.runJavascriptWithAsyncResult(getWebContents(),
+                "readyToStartPromise.then(() => domAutomationController.send(true));");
+    }
+
+    // After calling createTransitionAndWaitUntilDomUpdateDispatched to create a transition, this
+    // will continue the transition and start the animation.
+    private void startTransitionAnimation() throws Throwable {
+        JavaScriptUtils.executeJavaScriptAndWaitForResult(
+                getWebContents(), "startTransitionAnimation();");
+    }
+
+    // Force generating a new compositor frame from the renderer and wait until
+    // its presented on screen.
+    private void waitForFramePresented() throws Throwable {
+        final CallbackHelper ch = new CallbackHelper();
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            getWebContents().getMainFrame().insertVisualStateCallback(result -> ch.notifyCalled());
+        });
+
+        ch.waitForNext(TEST_TIMEOUT, TimeUnit.SECONDS);
+
+        // insertVisualStateCallback replies when a CompositorFrame is submitted. However, we want
+        // to wait until the Viz process has received the new CompositorFrame so that the new frame
+        // is available to a CopySurfaceRequest. Waiting for a second frame to be submitted
+        // guarantees this since it cannot be sent until the first frame was ACKed by Viz.
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            getWebContents().getMainFrame().insertVisualStateCallback(result -> ch.notifyCalled());
+        });
+
+        ch.waitForNext(TEST_TIMEOUT, TimeUnit.SECONDS);
+    }
+
+    private boolean doPixelsApproximatelyMatch(int expected, int actual, int threshold) {
+        return Math.abs(Color.red(expected) - Color.red(actual)) < threshold
+                && Math.abs(Color.green(expected) - Color.green(actual)) < threshold
+                && Math.abs(Color.blue(expected) - Color.blue(actual)) < threshold;
+    }
+
+    // Compares the expected to the actual screenshot bitmaps and returns true if they're
+    // equivalent. Some fuzziness is allowed to account for blending and compositing artifacts. If
+    // failed, the test is failed with a message containing paths to a data: URL for each of the
+    // bitmaps. These can be easily viewed using `adb shell cat filename` and copied into a browser
+    // for viewing.
+    private boolean doPixelTestScreenshotsMatch(Bitmap expected, Bitmap actual) throws Throwable {
+        Assert.assertEquals(expected.getWidth(), actual.getWidth());
+        Assert.assertEquals(expected.getHeight(), actual.getHeight());
+
+        int failingPixels = 0;
+        for (int y = 0; y < expected.getHeight(); ++y) {
+            for (int x = 0; x < expected.getWidth(); ++x) {
+                int expectedColor = expected.getPixel(x, y);
+                int actualColor = actual.getPixel(x, y);
+
+                if (!doPixelsApproximatelyMatch(
+                            expectedColor, actualColor, PIXEL_COLOR_CHANNEL_DIFF_FUZZINESS)) {
+                    ++failingPixels;
+                }
+            }
+        }
+
+        if (failingPixels > PIXEL_DIFF_FUZZINESS) {
+            String url_expected = bitmapToDataUrl(expected);
+            String url_actual = bitmapToDataUrl(actual);
+            Assert.fail("Does not match reference screenshot, " + failingPixels
+                    + " pixels differed.\n"
+                    + " Expected screenshot (" + url_expected + ")\n"
+                    + " Actual screenshot(" + url_actual + ")");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Test view transitions when going from a state with a virtual keyboard shown to the virtual
+     * keyboard hidden.
+     *
+     * This tests the default mode where the virtual-keyboard resizes only the visual viewport and
+     * the author hasn't opted into a content-resizing virtual keyboard.
+     */
+    @Test
+    @MediumTest
+    public void testVirtualKeyboardResizesVisualOld() throws Throwable {
+        startTest(VirtualKeyboardMode.RESIZES_VISUAL, CAPTURE_OLD);
+
+        // Since the keyboard affects only the visual viewport, the initial page is how we expect
+        // the transition snapshot to look when the keyboard is hidden.
+        Bitmap expected = takeScreenshot();
+
+        showAndWaitForKeyboard();
+
+        createTransitionAndWaitUntilDomUpdateDispatched();
+
+        // Note: rendering is blocked here so we can't wait for the keyboard to hide since the size
+        // depends on the renderer.
+        hideKeyboard();
+
+        // Start the animation. The "animation" simply displays the old transition for the full
+        // duration of the test.
+        startTransitionAnimation();
+
+        waitForKeyboardHidden();
+
+        // Wait for a frame to be presented to ensure the animation has started and the updated
+        // viewport size is rendered.
+        waitForFramePresented();
+
+        Bitmap actual = takeScreenshot();
+
+        Assert.assertTrue(doPixelTestScreenshotsMatch(expected, actual));
+    }
+
+    /**
+     * Test view transitions when going from a state with a virtual keyboard shown to the virtual
+     * keyboard hidden.
+     *
+     * This tests the mode where the author opts in to the keyboard resizing page content.
+     */
+    @Test
+    @MediumTest
+    public void testVirtualKeyboardResizesContentOld() throws Throwable {
+        startTest(VirtualKeyboardMode.RESIZES_CONTENT, CAPTURE_OLD);
+
+        // Since the keyboard affects content it'll push the bottom-fixed element up. Push it up
+        // manually to take the expected screenshot.
+        {
+            showAndWaitForKeyboard();
+
+            double keyboardHeight = getKeyboardHeightDp();
+
+            hideKeyboard();
+            waitForKeyboardHidden();
+
+            JavaScriptUtils.executeJavaScriptAndWaitForResult(getWebContents(),
+                    "document.getElementById('bottomfixed').style.transform ="
+                            + "'translateY(-" + keyboardHeight + "px)';");
+
+            waitForFramePresented();
+        }
+
+        Bitmap expected = takeScreenshot();
+
+        {
+            JavaScriptUtils.executeJavaScriptAndWaitForResult(getWebContents(),
+                    "document.getElementById('bottomfixed').style.transform = '';");
+        }
+
+        showAndWaitForKeyboard();
+
+        createTransitionAndWaitUntilDomUpdateDispatched();
+
+        // Note: rendering is blocked here so we can't wait for the keyboard to hide since the size
+        // depends on the renderer.
+        hideKeyboard();
+
+        // Start the animation. The "animation" simply displays the old transition for the full
+        // duration of the test.
+        startTransitionAnimation();
+
+        waitForKeyboardHidden();
+
+        // Wait for a frame to be presented to ensure the animation has started and the updated
+        // viewport size is rendered.
+        waitForFramePresented();
+
+        Bitmap actual = takeScreenshot();
+
+        Assert.assertTrue(doPixelTestScreenshotsMatch(expected, actual));
+    }
+
+    /**
+     * Test view transitions when going from a state with a virtual keyboard shown to the virtual
+     * keyboard hidden.
+     *
+     * This tests the mode where the author opts in to the keyboard resizing page content.
+     */
+    @Test
+    @MediumTest
+    public void testVirtualKeyboardResizesContentNew() throws Throwable {
+        startTest(VirtualKeyboardMode.RESIZES_CONTENT, CAPTURE_NEW);
+
+        Bitmap expected;
+
+        // Since this test checks new state, the keyboard will be down so all that must be done
+        // for the reference screenshot is to update the DOM to the final state.
+        {
+            JavaScriptUtils.executeJavaScriptAndWaitForResult(getWebContents(), "updateDOM()");
+            waitForFramePresented();
+
+            expected = takeScreenshot();
+
+            JavaScriptUtils.executeJavaScriptAndWaitForResult(getWebContents(), "undoUpdateDOM()");
+        }
+
+        showAndWaitForKeyboard();
+
+        createTransitionAndWaitUntilDomUpdateDispatched();
+
+        // Note: rendering is blocked here so we can't wait for the keyboard to hide since the size
+        // depends on the renderer.
+        hideKeyboard();
+
+        // Start the animation. The "animation" simply displays the new transition for the full
+        // duration of the test.
+        startTransitionAnimation();
+
+        waitForKeyboardHidden();
+
+        // Wait for a frame to be presented to ensure the animation has started and the updated
+        // viewport size is rendered.
+        waitForFramePresented();
+
+        Bitmap actual = takeScreenshot();
+
+        Assert.assertTrue(doPixelTestScreenshotsMatch(expected, actual));
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/OWNERS
deleted file mode 100644
index 9e31bde3..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://chrome/android/java/src/org/chromium/chrome/browser/display_cutout/OWNERS
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offline/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/offline/OWNERS
index 0dacbc4..723d43d2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offline/OWNERS
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offline/OWNERS
@@ -1 +1 @@
-file://chrome/android/java/src/org/chromium/chrome/browser/offline/OWNERS
+file://chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
index 38ebce0..34992bb 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
@@ -258,7 +258,8 @@
     public TabImpl prepareTab() {
         TabImpl tab = mock(TabImpl.class);
         when(tab.getView()).thenReturn(mock(View.class));
-        when(tab.getUserDataHost()).thenReturn(new UserDataHost());
+        UserDataHost host = new UserDataHost();
+        when(tab.getUserDataHost()).thenReturn(host);
         WebContents webContents = mock(WebContents.class);
         when(tab.getWebContents()).thenReturn(webContents);
         NavigationController navigationController = mock(NavigationController.class);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java
index 6ffc930f..1d6774f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java
@@ -106,5 +106,11 @@
         public boolean hadInteraction(long nativeTabInteractionRecorderAndroid) {
             return paramHadInteraction;
         }
+
+        @Override
+        public void reset(long nativeTabInteractionRecorderAndroid) {
+            paramHadInteraction = false;
+            paramDidGetUserInteraction = false;
+        }
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerUnitTest.java
index c276818..35b5631 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/SessionRestoreManagerUnitTest.java
@@ -4,38 +4,103 @@
 
 package org.chromium.chrome.browser.customtabs.features.sessionrestore;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.annotation.LooperMode.Mode;
+import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.shadows.ShadowSystemClock;
 
+import org.chromium.base.task.TaskTraits;
+import org.chromium.base.task.test.ShadowPostTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Features;
+import org.chromium.base.test.util.PayloadCallbackHelper;
+import org.chromium.chrome.browser.app.tab_activity_glue.ReparentingTask;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityContentTestEnvironment;
+import org.chromium.chrome.browser.customtabs.features.TabInteractionRecorder;
+import org.chromium.chrome.browser.customtabs.features.sessionrestore.SessionRestoreManagerImpl.EvictionReason;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.tab.Tab;
+
+import java.util.concurrent.TimeUnit;
 
 /**
  * Unit test related to {@link SessionRestoreManager}.
  */
 @RunWith(BaseRobolectricTestRunner.class)
+@Config(shadows = {ShadowLooper.class, ShadowPostTask.class})
+@LooperMode(Mode.PAUSED)
 public class SessionRestoreManagerUnitTest {
+    private static final int TEST_EVICTION_TIMEOUT = 10;
+
     @Rule
     public CustomTabActivityContentTestEnvironment env =
             new CustomTabActivityContentTestEnvironment();
     @Rule
     public TestRule mFeatureProcessor = new Features.JUnitProcessor();
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Mock
+    TabFreezer mTabFreezer;
+    @Mock
+    TabInteractionRecorder mTabInteractionRecorder;
+
+    private SessionRestoreManager mSessionRestoreManager;
+    private @EvictionReason PayloadCallbackHelper<Integer> mEvictionCallback;
+    private Tab mTab;
 
     @Before
     public void setup() {
-        Mockito.doCallRealMethod().when(env.connection).getSessionRestoreManager();
+        ShadowPostTask.setTestImpl(new ShadowPostTask.TestImpl() {
+            final Handler mHandler = new Handler(Looper.getMainLooper());
+
+            @Override
+            public void postDelayedTask(TaskTraits taskTraits, Runnable task, long delay) {
+                mHandler.postDelayed(task, delay);
+            }
+        });
+        mTab = env.prepareTab();
+        mEvictionCallback = new PayloadCallbackHelper<>();
+        TabInteractionRecorder.setInstanceForTesting(mTabInteractionRecorder);
+        mSessionRestoreManager = new SessionRestoreManagerImpl(mTabFreezer);
+        mSessionRestoreManager.addObserver(mEvictionCallback::notifyCalled);
+        mSessionRestoreManager.setEvictionTimeout(TEST_EVICTION_TIMEOUT);
+        doReturn(true).when(mTabFreezer).freeze(any());
+    }
+
+    @After
+    public void tearDown() {
+        TabInteractionRecorder.setInstanceForTesting(null);
+        ShadowPostTask.setTestImpl(null);
     }
 
     @Test
     @Features.EnableFeatures(ChromeFeatureList.CCT_RETAINING_STATE_IN_MEMORY)
     public void getSessionManagerWithFeature() {
+        Mockito.doCallRealMethod().when(env.connection).getSessionRestoreManager();
         Assert.assertNotNull(
                 "SessionRestoreManager is null.", env.connection.getSessionRestoreManager());
     }
@@ -43,7 +108,58 @@
     @Test
     @Features.DisableFeatures(ChromeFeatureList.CCT_RETAINING_STATE_IN_MEMORY)
     public void nullSessionManagerWithoutFeature() {
+        Mockito.doCallRealMethod().when(env.connection).getSessionRestoreManager();
         Assert.assertNull(
                 "SessionRestoreManager should be null.", env.connection.getSessionRestoreManager());
     }
+
+    @Test
+    public void storeThenEvictedByTimeout() {
+        assertTrue("Tab store failed.", mSessionRestoreManager.store(mTab));
+        assertNotNull("ReparentingTask is not created for stored tab.",
+                mTab.getUserDataHost().getUserData(ReparentingTask.class));
+        verify(mTabInteractionRecorder).onTabClosing();
+
+        ShadowSystemClock.advanceBy(TEST_EVICTION_TIMEOUT, TimeUnit.MILLISECONDS);
+        Shadows.shadowOf(Looper.getMainLooper()).runOneTask();
+
+        assertEvictedWithReason(EvictionReason.TIMEOUT);
+    }
+
+    @Test
+    public void callClearCache() {
+        doReturn(true).when(mTabFreezer).hasTab();
+        mSessionRestoreManager.clearCache();
+
+        assertEvictedWithReason(EvictionReason.CLIENT_CLEAN);
+    }
+
+    @Test
+    public void restoreTab() {
+        doReturn(true).when(mTabFreezer).hasTab();
+        doReturn(mTab).when(mTabFreezer).unfreeze();
+
+        assertEquals("Restoring tab failed.", mTab, mSessionRestoreManager.restoreTab());
+        verify(mTabInteractionRecorder).reset();
+        verify(mTabFreezer).unfreeze();
+    }
+
+    @Test
+    public void storeNewTabOverridePreviousTab() {
+        // This is a temporary test where we only support storing one tab.
+        // TODO(https://crbug.com/1379452): Remove when support freezing multiple tabs.
+        doReturn(true).when(mTabFreezer).hasTab();
+        assertTrue("Tab store failed.", mSessionRestoreManager.store(mTab));
+        assertNotNull("ReparentingTask is not created for stored tab.",
+                mTab.getUserDataHost().getUserData(ReparentingTask.class));
+        verify(mTabInteractionRecorder).onTabClosing();
+        assertEvictedWithReason(EvictionReason.NEW_TAB_OVERRIDE);
+    }
+
+    private void assertEvictedWithReason(@EvictionReason int reason) {
+        verify(mTabFreezer).clear();
+        assertTrue("evictionCallback should be invoked.", mEvictionCallback.getCallCount() > 0);
+        assertEquals("Eviction reason is different.", reason,
+                (int) mEvictionCallback.getOnlyPayloadBlocking());
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/TabFreezerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/TabFreezerUnitTest.java
new file mode 100644
index 0000000..bc57f9e
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/sessionrestore/TabFreezerUnitTest.java
@@ -0,0 +1,77 @@
+// 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.features.sessionrestore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.tab.Tab;
+
+/**
+ * Unit tests for {@link TabFreezer}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+public class TabFreezerUnitTest {
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+
+    private TabFreezer mTabFreezer;
+
+    @Mock
+    private Tab mTab;
+
+    @Before
+    public void setup() {
+        mTabFreezer = new TabFreezer();
+    }
+
+    @Test
+    public void emptyFreeze() {
+        assertFalse("No tab exists in empty freezer.", mTabFreezer.hasTab());
+        assertEquals("No tab to be cleared.", Tab.INVALID_TAB_ID, mTabFreezer.clear());
+        assertNull("No tab to unfreeze.", mTabFreezer.unfreeze());
+    }
+
+    @Test
+    public void freezeTabThenRestore() {
+        mTabFreezer.freeze(mTab);
+        verify(mTab).hide(anyInt());
+        assertTrue("Freezer should have tab.", mTabFreezer.hasTab());
+
+        Tab unfrozenTab = mTabFreezer.unfreeze();
+        assertEquals("Unfrozen tab changed.", mTab, unfrozenTab);
+        assertFalse("No tab exists after unfreeze.", mTabFreezer.hasTab());
+    }
+
+    @Test
+    public void freezeTabThenClear() {
+        final int testTabId = 6173; // Arbitrary number.
+        doReturn(testTabId).when(mTab).getId();
+        mTabFreezer.freeze(mTab);
+        verify(mTab).hide(anyInt());
+        assertTrue("Freezer should have tab.", mTabFreezer.hasTab());
+
+        int clearedTabId = mTabFreezer.clear();
+        verify(mTab).getId();
+        verify(mTab).destroy();
+        assertEquals("Removed tabId does not match.", testTabId, clearedTabId);
+        assertFalse("No tab exists in after clear.", mTabFreezer.hasTab());
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/OWNERS
deleted file mode 100644
index 9e31bde3..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://chrome/android/java/src/org/chromium/chrome/browser/display_cutout/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/OWNERS
index 4cf87a226..dea93c8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/OWNERS
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/OWNERS
@@ -1 +1 @@
-file://chrome/android/java/src/org/chromium/chrome/browser/search_engines/OWNERS
+file://chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/OWNERS
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 73f1f77..831ef6f7 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -95,6 +95,7 @@
 buildflag_header("buildflags") {
   header = "buildflags.h"
   flags = [
+    "ENABLE_UPDATER=$enable_updater",
     "ENABLE_UPDATE_NOTIFICATIONS=$enable_update_notifications",
     "USE_MINIKIN_HYPHENATION=$use_minikin_hyphenation",
     "USE_THIN_LTO=$use_thin_lto",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 6bd91097..b0b905e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6827,11 +6827,6 @@
      flag_descriptions::kEnhancedNetworkVoicesDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kEnhancedNetworkVoices)},
 
-    {"enable-accessibility-os-settings-visibility",
-     flag_descriptions::kAccessibilityOSSettingsVisibilityName,
-     flag_descriptions::kAccessibilityOSSettingsVisibilityDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kAccessibilityOSSettingsVisibility)},
-
     {"enable-accessibility-service",
      flag_descriptions::kAccessibilityServiceName,
      flag_descriptions::kAccessibilityServiceDescription, kOsCrOS,
diff --git a/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc b/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc
index 6c119de..68a3fc0d 100644
--- a/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc
+++ b/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc
@@ -175,6 +175,10 @@
   return static_cast<jboolean>(has_interaction);
 }
 
+void TabInteractionRecorderAndroid::Reset(JNIEnv* env) {
+  has_form_interactions_ = false;
+}
+
 ScopedJavaLocalRef<jobject> JNI_TabInteractionRecorder_GetFromTab(
     JNIEnv* env,
     const JavaParamRef<jobject>& jtab) {
diff --git a/chrome/browser/android/customtabs/tab_interaction_recorder_android.h b/chrome/browser/android/customtabs/tab_interaction_recorder_android.h
index c90178f..b4232b4 100644
--- a/chrome/browser/android/customtabs/tab_interaction_recorder_android.h
+++ b/chrome/browser/android/customtabs/tab_interaction_recorder_android.h
@@ -84,6 +84,7 @@
   // JNI methods
   jboolean DidGetUserInteraction(JNIEnv* env) const;
   jboolean HadInteraction(JNIEnv* env) const;
+  void Reset(JNIEnv* env);
 
 #ifdef UNIT_TEST
   void SetAutofillManagerForTest(
diff --git a/chrome/browser/ash/base/locale_util.h b/chrome/browser/ash/base/locale_util.h
index a54ea9e3..669b7e13 100644
--- a/chrome/browser/ash/base/locale_util.h
+++ b/chrome/browser/ash/base/locale_util.h
@@ -96,18 +96,4 @@
 }  // namespace locale_util
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after //chrome/browser/chromeos
-// source migration is finished.
-namespace chromeos {
-namespace locale_util {
-using ::ash::locale_util::GetAllowedFallbackUILanguage;
-using ::ash::locale_util::IsAllowedLanguage;
-using ::ash::locale_util::IsAllowedUILanguage;
-using ::ash::locale_util::LanguageSwitchResult;
-using ::ash::locale_util::RemoveDisallowedLanguagesFromPreferred;
-using ::ash::locale_util::SwitchLanguage;
-using ::ash::locale_util::SwitchLanguageCallback;
-}  // namespace locale_util
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_BASE_LOCALE_UTIL_H_
diff --git a/chrome/browser/ash/bluetooth/debug_logs_manager_factory.h b/chrome/browser/ash/bluetooth/debug_logs_manager_factory.h
index 9a16eb22..3af45039 100644
--- a/chrome/browser/ash/bluetooth/debug_logs_manager_factory.h
+++ b/chrome/browser/ash/bluetooth/debug_logs_manager_factory.h
@@ -42,12 +42,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
-// done.
-namespace chromeos {
-namespace bluetooth {
-using ::ash::bluetooth::DebugLogsManagerFactory;
-}  // namespace bluetooth
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_BLUETOOTH_DEBUG_LOGS_MANAGER_FACTORY_H_
diff --git a/chrome/browser/ash/borealis/borealis_features.cc b/chrome/browser/ash/borealis/borealis_features.cc
index ace8a40..d0123c00 100644
--- a/chrome/browser/ash/borealis/borealis_features.cc
+++ b/chrome/browser/ash/borealis/borealis_features.cc
@@ -226,7 +226,7 @@
   if (!profile_ || !profile_->IsRegularProfile())
     return AllowStatus::kBlockedOnIrregularProfile;
 
-  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile_))
+  if (!ash::ProfileHelper::IsPrimaryProfile(profile_))
     return AllowStatus::kBlockedOnNonPrimaryProfile;
 
   if (profile_->IsChild())
diff --git a/chrome/browser/ash/browser_accelerator_configuration.cc b/chrome/browser/ash/browser_accelerator_configuration.cc
index dc3e01d..cdf2672 100644
--- a/chrome/browser/ash/browser_accelerator_configuration.cc
+++ b/chrome/browser/ash/browser_accelerator_configuration.cc
@@ -10,7 +10,7 @@
 namespace ash {
 
 BrowserAcceleratorConfiguration::BrowserAcceleratorConfiguration()
-    : AcceleratorConfiguration(ash::mojom::AcceleratorSource::kBrowser) {}
+    : AcceleratorConfiguration(mojom::AcceleratorSource::kBrowser) {}
 
 BrowserAcceleratorConfiguration::~BrowserAcceleratorConfiguration() = default;
 
diff --git a/chrome/browser/ash/browser_context_keyed_service_factories.cc b/chrome/browser/ash/browser_context_keyed_service_factories.cc
index 4ddf2d0d..f615e81 100644
--- a/chrome/browser/ash/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/ash/browser_context_keyed_service_factories.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ash/borealis/borealis_service_factory.h"
 #include "chrome/browser/ash/bruschetta/bruschetta_service_factory.h"
 #include "chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.h"
+#include "chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive.h"
 #include "chrome/browser/ash/crostini/crostini_engagement_metrics_service.h"
 #include "chrome/browser/ash/eche_app/eche_app_manager_factory.h"
 #include "chrome/browser/ash/extensions/file_manager/event_router_factory.h"
@@ -64,6 +65,7 @@
   bruschetta::BruschettaServiceFactory::GetInstance();
   CastMediaNotificationProducerKeyedServiceFactory::GetInstance();
   cert_provisioning::CertProvisioningSchedulerUserServiceFactory::GetInstance();
+  crosapi::PersistentForcedExtensionKeepAliveFactory::GetInstance();
   crostini::CrostiniEngagementMetricsService::Factory::GetInstance();
 #if defined(USE_CUPS)
   CupsProxyServiceManagerFactory::GetInstance();
diff --git a/chrome/browser/ash/camera_mic/vm_camera_mic_manager.cc b/chrome/browser/ash/camera_mic/vm_camera_mic_manager.cc
index 0c92c7b..a1badbc 100644
--- a/chrome/browser/ash/camera_mic/vm_camera_mic_manager.cc
+++ b/chrome/browser/ash/camera_mic/vm_camera_mic_manager.cc
@@ -43,6 +43,7 @@
 #include "ui/message_center/public/cpp/notification_types.h"
 
 namespace ash {
+
 namespace {
 
 const char kNotificationIdPrefix[] = "vm_camera_mic_manager";
@@ -214,8 +215,8 @@
     }
     notifications_.active = new_notification;
 
-    if (ash::features::IsPrivacyIndicatorsEnabled()) {
-      ash::UpdatePrivacyIndicatorsView(
+    if (features::IsPrivacyIndicatorsEnabled()) {
+      UpdatePrivacyIndicatorsView(
           /*app_id=*/GetNotificationId(vm_type_, new_notification),
           /*is_camera_used=*/
           new_notification[static_cast<size_t>(DeviceType::kCamera)],
@@ -275,9 +276,9 @@
     rich_notification_data.fullscreen_visibility =
         message_center::FullscreenVisibility::OVER_USER;
 
-    if (ash::features::IsPrivacyIndicatorsEnabled()) {
+    if (features::IsPrivacyIndicatorsEnabled()) {
       // We will use the notification id's logic here for `app_id`
-      auto notification = ash::CreatePrivacyIndicatorsNotification(
+      auto notification = CreatePrivacyIndicatorsNotification(
           GetNotificationId(vm_type_, type),
           l10n_util::GetStringUTF16(name_id_),
           type[static_cast<size_t>(DeviceType::kCamera)],
@@ -306,7 +307,7 @@
         /*origin_url=*/GURL(),
         message_center::NotifierId(
             message_center::NotifierType::SYSTEM_COMPONENT,
-            ash::kVmCameraMicNotifierId, NotificationCatalogName::kVMCameraMic),
+            kVmCameraMicNotifierId, NotificationCatalogName::kVMCameraMic),
         rich_notification_data,
         base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
             weak_ptr_factory_.GetMutableWeakPtr()));
diff --git a/chrome/browser/ash/camera_mic/vm_camera_mic_manager.h b/chrome/browser/ash/camera_mic/vm_camera_mic_manager.h
index cf5a884..dd7278d3 100644
--- a/chrome/browser/ash/camera_mic/vm_camera_mic_manager.h
+++ b/chrome/browser/ash/camera_mic/vm_camera_mic_manager.h
@@ -115,10 +115,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
-// done.
-namespace chromeos {
-using ::ash::VmCameraMicManager;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CAMERA_MIC_VM_CAMERA_MIC_MANAGER_H_
diff --git a/chrome/browser/ash/camera_mic/vm_camera_mic_manager_unittest.cc b/chrome/browser/ash/camera_mic/vm_camera_mic_manager_unittest.cc
index 131ae24..c8324d6 100644
--- a/chrome/browser/ash/camera_mic/vm_camera_mic_manager_unittest.cc
+++ b/chrome/browser/ash/camera_mic/vm_camera_mic_manager_unittest.cc
@@ -35,11 +35,13 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/test/display_manager_test_api.h"
 
+namespace ash {
+
 namespace {
-using testing::UnorderedElementsAre;
-using VmType = ash::VmCameraMicManager::VmType;
-using DeviceType = ash::VmCameraMicManager::DeviceType;
-using NotificationType = ash::VmCameraMicManager::NotificationType;
+
+using VmType = VmCameraMicManager::VmType;
+using DeviceType = VmCameraMicManager::DeviceType;
+using NotificationType = VmCameraMicManager::NotificationType;
 
 constexpr VmType kCrostiniVm = VmType::kCrostiniVm;
 constexpr VmType kPluginVm = VmType::kPluginVm;
@@ -49,13 +51,13 @@
 constexpr DeviceType kMic = DeviceType::kMic;
 
 constexpr NotificationType kMicNotification =
-    ash::VmCameraMicManager::kMicNotification;
+    VmCameraMicManager::kMicNotification;
 constexpr NotificationType kCameraNotification =
-    ash::VmCameraMicManager::kCameraNotification;
+    VmCameraMicManager::kCameraNotification;
 constexpr NotificationType kCameraAndMicNotification =
-    ash::VmCameraMicManager::kCameraAndMicNotification;
+    VmCameraMicManager::kCameraAndMicNotification;
 
-constexpr auto kDebounceTime = ash::VmCameraMicManager::kDebounceTime;
+constexpr auto kDebounceTime = VmCameraMicManager::kDebounceTime;
 
 class FakeNotificationDisplayService : public NotificationDisplayService {
  public:
@@ -98,8 +100,8 @@
 
 // Check the visibility of privacy indicators in all displays.
 void ExpectPrivacyIndicatorsVisible(bool visible) {
-  for (ash::RootWindowController* root_window_controller :
-       ash::Shell::Get()->GetAllRootWindowControllers()) {
+  for (RootWindowController* root_window_controller :
+       Shell::Get()->GetAllRootWindowControllers()) {
     EXPECT_EQ(root_window_controller->GetStatusAreaWidget()
                   ->unified_system_tray()
                   ->privacy_indicators_view()
@@ -110,8 +112,6 @@
 
 }  // namespace
 
-namespace ash {
-
 class VmCameraMicManagerTest : public testing::Test {
  public:
   // Define here to access `VmCameraMicManager` private members.
@@ -276,7 +276,7 @@
   void SetUp() override {
     scoped_feature_list_.InitWithFeatures(
         {apps::kAppServiceCapabilityAccessWithoutMojom,
-         ash::features::kPrivacyIndicators},
+         features::kPrivacyIndicators},
         {});
 
     VmCameraMicManagerTest::SetUp();
@@ -308,7 +308,7 @@
 
 TEST_F(VmCameraMicManagerPrivacyIndicatorsTest, PrivacyIndicatorsView) {
   // Make sure privacy indicators work on multiple displays.
-  display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
+  display::test::DisplayManagerTestApi(Shell::Get()->display_manager())
       .UpdateDisplay("800x800,801+0-800x800");
 
   SetCameraAccessing(kPluginVm, false);
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.h b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.h
index b7f2cdb..85a6c13 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.h
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_user_service.h
@@ -47,12 +47,4 @@
 }  // namespace cert_provisioning
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
-// done.
-namespace chromeos {
-namespace cert_provisioning {
-using ::ash::cert_provisioning::CertProvisioningSchedulerUserServiceFactory;
-}  // namespace cert_provisioning
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CERT_PROVISIONING_CERT_PROVISIONING_SCHEDULER_USER_SERVICE_H_
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_unittest.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_unittest.cc
index 24a865ba..0b64c60a 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_unittest.cc
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker_unittest.cc
@@ -48,8 +48,7 @@
 
 namespace em = ::enterprise_management;
 
-using ::ash::attestation::MockTpmChallengeKeySubtle;
-using ::ash::platform_keys::KeyUsage;
+using attestation::MockTpmChallengeKeySubtle;
 using ::base::test::IsJson;
 using ::base::test::ParseJson;
 using ::base::test::RunOnceCallback;
@@ -57,6 +56,7 @@
 using ::chromeos::platform_keys::KeyAttributeType;
 using ::chromeos::platform_keys::Status;
 using ::chromeos::platform_keys::TokenId;
+using platform_keys::KeyUsage;
 using ::testing::_;
 using ::testing::AtLeast;
 using ::testing::Mock;
diff --git a/chrome/browser/ash/child_accounts/child_account_test_utils.h b/chrome/browser/ash/child_accounts/child_account_test_utils.h
index 37d01bb..436148d8 100644
--- a/chrome/browser/ash/child_accounts/child_account_test_utils.h
+++ b/chrome/browser/ash/child_accounts/child_account_test_utils.h
@@ -16,11 +16,4 @@
 }  // namespace test
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-namespace test {
-using ::ash::test::GetChildAccountOAuthIdToken;
-}  // namespace test
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_CHILD_ACCOUNT_TEST_UTILS_H_
diff --git a/chrome/browser/ash/child_accounts/child_policy_observer.h b/chrome/browser/ash/child_accounts/child_policy_observer.h
index 4a5d8e13..5733f4c 100644
--- a/chrome/browser/ash/child_accounts/child_policy_observer.h
+++ b/chrome/browser/ash/child_accounts/child_policy_observer.h
@@ -94,9 +94,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-using ::ash::ChildPolicyObserver;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_CHILD_POLICY_OBSERVER_H_
diff --git a/chrome/browser/ash/child_accounts/child_status_reporting_service_factory.h b/chrome/browser/ash/child_accounts/child_status_reporting_service_factory.h
index ccb5d73..878441e 100644
--- a/chrome/browser/ash/child_accounts/child_status_reporting_service_factory.h
+++ b/chrome/browser/ash/child_accounts/child_status_reporting_service_factory.h
@@ -44,9 +44,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-using ::ash::ChildStatusReportingServiceFactory;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_CHILD_STATUS_REPORTING_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ash/child_accounts/child_user_service.h b/chrome/browser/ash/child_accounts/child_user_service.h
index 2d31184..26e5fdb 100644
--- a/chrome/browser/ash/child_accounts/child_user_service.h
+++ b/chrome/browser/ash/child_accounts/child_user_service.h
@@ -124,9 +124,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-using ::ash::ChildUserService;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_CHILD_USER_SERVICE_H_
diff --git a/chrome/browser/ash/child_accounts/edu_coexistence_tos_store_utils.h b/chrome/browser/ash/child_accounts/edu_coexistence_tos_store_utils.h
index e4796e3..0c56dbc 100644
--- a/chrome/browser/ash/child_accounts/edu_coexistence_tos_store_utils.h
+++ b/chrome/browser/ash/child_accounts/edu_coexistence_tos_store_utils.h
@@ -14,8 +14,8 @@
 namespace edu_coexistence {
 
 // The first google3 cl number that is sent through a policy which is mapped
-// to |ash::prefs::kEduCoexistenceToSVersion|. All version numbers sent
-// will be greater than or equal to |kMinTOSVersionNumber|.
+// to `prefs::kEduCoexistenceToSVersion`. All version numbers sent
+// will be greater than or equal to `kMinTOSVersionNumber`.
 extern const char kMinTOSVersionNumber[];
 
 // Used to store the gaia id and corresponding accepted terms of
@@ -38,8 +38,8 @@
 // If the account already exists in user's pref, then its accepted tos will be
 // updated. Otherwise, a new entry will be created.
 // The pref that is used to store the UserConsentInfo is defined in:
-// |ash::prefs::kEduCoexistenceToSAcceptedVersion|
-// Unlike |SetUserConsentInfoListForProfile| this doesn't overwrite the entire
+// `prefs::kEduCoexistenceToSAcceptedVersion`
+// Unlike `SetUserConsentInfoListForProfile` this doesn't overwrite the entire
 // stored UserConsentInfo list; it instead updates it.
 void UpdateAcceptedToSVersionPref(Profile* profile,
                                   const UserConsentInfo& user_consent_info);
@@ -50,7 +50,7 @@
     const std::vector<UserConsentInfo>& user_consent_info_list);
 
 // Returns the list of UserConsentInfo stored in
-// |ash::prefs::kEduCoexistenceToSAcceptedVersion|.
+// `prefs::kEduCoexistenceToSAcceptedVersion`.
 std::vector<UserConsentInfo> GetUserConsentInfoListForProfile(Profile* profile);
 
 // |profile| is the Primary user profile which is the family link user.
diff --git a/chrome/browser/ash/child_accounts/family_features.h b/chrome/browser/ash/child_accounts/family_features.h
index bfae83f..10ed821d 100644
--- a/chrome/browser/ash/child_accounts/family_features.h
+++ b/chrome/browser/ash/child_accounts/family_features.h
@@ -16,10 +16,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-using ::ash::IsFamilyLinkOobeHandoffEnabled;
-using ::ash::kFamilyLinkOobeHandoff;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_FAMILY_FEATURES_H_
diff --git a/chrome/browser/ash/child_accounts/family_user_metrics_service_factory.h b/chrome/browser/ash/child_accounts/family_user_metrics_service_factory.h
index be69d6a..9b8dfb83 100644
--- a/chrome/browser/ash/child_accounts/family_user_metrics_service_factory.h
+++ b/chrome/browser/ash/child_accounts/family_user_metrics_service_factory.h
@@ -44,9 +44,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-using ::ash::FamilyUserMetricsServiceFactory;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_FAMILY_USER_METRICS_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ash/child_accounts/parent_access_code/parent_access_service.h b/chrome/browser/ash/child_accounts/parent_access_code/parent_access_service.h
index 6aaf350..4e4157a 100644
--- a/chrome/browser/ash/child_accounts/parent_access_code/parent_access_service.h
+++ b/chrome/browser/ash/child_accounts/parent_access_code/parent_access_service.h
@@ -89,12 +89,4 @@
 }  // namespace parent_access
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
-// done.
-namespace chromeos {
-namespace parent_access {
-using ::ash::parent_access::ParentAccessService;
-}  // namespace parent_access
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_PARENT_ACCESS_CODE_PARENT_ACCESS_SERVICE_H_
diff --git a/chrome/browser/ash/child_accounts/screen_time_controller.cc b/chrome/browser/ash/child_accounts/screen_time_controller.cc
index fc1bfb0..0c17511 100644
--- a/chrome/browser/ash/child_accounts/screen_time_controller.cc
+++ b/chrome/browser/ash/child_accounts/screen_time_controller.cc
@@ -45,20 +45,20 @@
 constexpr char kScreenStateNextPolicyType[] = "next_active_policy";
 constexpr char kScreenStateNextUnlockTime[] = "next_unlock_time";
 
-ash::AuthDisabledReason ConvertLockReason(
+AuthDisabledReason ConvertLockReason(
     usage_time_limit::PolicyType active_policy) {
   switch (active_policy) {
     case usage_time_limit::PolicyType::kFixedLimit:
-      return ash::AuthDisabledReason::kTimeWindowLimit;
+      return AuthDisabledReason::kTimeWindowLimit;
     case usage_time_limit::PolicyType::kUsageLimit:
-      return ash::AuthDisabledReason::kTimeUsageLimit;
+      return AuthDisabledReason::kTimeUsageLimit;
     case usage_time_limit::PolicyType::kOverride:
-      return ash::AuthDisabledReason::kTimeLimitOverride;
+      return AuthDisabledReason::kTimeLimitOverride;
     case usage_time_limit::PolicyType::kNoPolicy:
       break;
   }
   NOTREACHED();
-  return ash::AuthDisabledReason();
+  return AuthDisabledReason();
 }
 
 }  // namespace
@@ -229,13 +229,13 @@
 }
 
 void ScreenTimeController::OnAccessCodeValidation(
-    ash::ParentCodeValidationResult result,
+    ParentCodeValidationResult result,
     absl::optional<AccountId> account_id) {
   AccountId current_user_id =
       ProfileHelper::Get()
           ->GetUserByProfile(Profile::FromBrowserContext(context_))
           ->GetAccountId();
-  if (result != ash::ParentCodeValidationResult::kValid || !account_id ||
+  if (result != ParentCodeValidationResult::kValid || !account_id ||
       account_id.value() != current_user_id)
     return;
 
@@ -266,14 +266,13 @@
           ->GetUserByProfile(Profile::FromBrowserContext(context_))
           ->GetAccountId();
   ScreenLocker::default_screen_locker()->TemporarilyDisableAuthForUser(
-      account_id,
-      ash::AuthDisabledData(ConvertLockReason(active_policy), next_unlock_time,
-                            GetScreenTimeDuration(),
-                            true /*disable_lock_screen_media*/));
+      account_id, AuthDisabledData(ConvertLockReason(active_policy),
+                                   next_unlock_time, GetScreenTimeDuration(),
+                                   true /*disable_lock_screen_media*/));
 
   // Add parent access code button.
   // TODO(agawronska): Move showing shelf button to ash.
-  ash::LoginScreen::Get()->ShowParentAccessButton(true);
+  LoginScreen::Get()->ShowParentAccessButton(true);
 }
 
 void ScreenTimeController::OnScreenLockByPolicyEnd() {
@@ -287,7 +286,7 @@
   ScreenLocker::default_screen_locker()->ReenableAuthForUser(account_id);
 
   // TODO(agawronska): Move showing shelf button to ash.
-  ash::LoginScreen::Get()->ShowParentAccessButton(false);
+  LoginScreen::Get()->ShowParentAccessButton(false);
 }
 
 void ScreenTimeController::OnPolicyChanged() {
diff --git a/chrome/browser/ash/child_accounts/screen_time_controller_browsertest.cc b/chrome/browser/ash/child_accounts/screen_time_controller_browsertest.cc
index 811e7f91..47bf03c 100644
--- a/chrome/browser/ash/child_accounts/screen_time_controller_browsertest.cc
+++ b/chrome/browser/ash/child_accounts/screen_time_controller_browsertest.cc
@@ -678,7 +678,7 @@
   EXPECT_FALSE(IsAuthEnabled());
 
   EXPECT_EQ(u"Come back at 17:00.",
-            ash::LoginScreenTestApi::GetDisabledAuthMessage(GetAccountId()));
+            LoginScreenTestApi::GetDisabledAuthMessage(GetAccountId()));
 }
 
 // Tests bedtime during timezone changes that make the clock go back in time.
diff --git a/chrome/browser/ash/child_accounts/screen_time_controller_factory.h b/chrome/browser/ash/child_accounts/screen_time_controller_factory.h
index 6d8d8b8..c4cb8fe85 100644
--- a/chrome/browser/ash/child_accounts/screen_time_controller_factory.h
+++ b/chrome/browser/ash/child_accounts/screen_time_controller_factory.h
@@ -42,9 +42,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-using ::ash::ScreenTimeControllerFactory;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_SCREEN_TIME_CONTROLLER_FACTORY_H_
diff --git a/chrome/browser/ash/child_accounts/time_limit_notifier.cc b/chrome/browser/ash/child_accounts/time_limit_notifier.cc
index 8f58c97..f232c663 100644
--- a/chrome/browser/ash/child_accounts/time_limit_notifier.cc
+++ b/chrome/browser/ash/child_accounts/time_limit_notifier.cc
@@ -52,7 +52,7 @@
   option_fields.fullscreen_visibility =
       message_center::FullscreenVisibility::OVER_USER;
   std::unique_ptr<message_center::Notification> notification =
-      ash::CreateSystemNotification(
+      CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
           message,
           l10n_util::GetStringUTF16(IDS_TIME_LIMIT_NOTIFICATION_DISPLAY_SOURCE),
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc b/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc
index ee4b4fd..c44dcbc 100644
--- a/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc
+++ b/chrome/browser/ash/child_accounts/time_limits/app_time_controller.cc
@@ -562,7 +562,7 @@
       message_center::FullscreenVisibility::OVER_USER;
 
   std::unique_ptr<message_center::Notification> message_center_notification =
-      ash::CreateSystemNotification(
+      CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
           message, notification_source, GURL(),
           message_center::NotifierId(
diff --git a/chrome/browser/ash/child_accounts/website_approval_notifier.cc b/chrome/browser/ash/child_accounts/website_approval_notifier.cc
index 12a7cec..5f8858a 100644
--- a/chrome/browser/ash/child_accounts/website_approval_notifier.cc
+++ b/chrome/browser/ash/child_accounts/website_approval_notifier.cc
@@ -88,7 +88,7 @@
   option_fields.fullscreen_visibility =
       message_center::FullscreenVisibility::OVER_USER;
   std::unique_ptr<message_center::Notification> notification =
-      ash::CreateSystemNotification(
+      CreateSystemNotification(
           message_center::NOTIFICATION_TYPE_SIMPLE,
           kWebsiteApprovalNotificationIdPrefix + allowed_host,
           l10n_util::GetStringUTF16(IDS_WEBSITE_APPROVED_NOTIFICATION_TITLE),
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
index 5fd31c2..4012eec 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -274,6 +274,7 @@
 #endif
 
 namespace ash {
+
 namespace {
 
 void ChromeOSVersionCallback(const absl::optional<std::string>& version) {
@@ -303,9 +304,8 @@
 }
 
 #if !defined(USE_REAL_DBUS_CLIENTS)
-ash::FakeSessionManagerClient* FakeSessionManagerClient() {
-  ash::FakeSessionManagerClient* fake_session_manager_client =
-      ash::FakeSessionManagerClient::Get();
+FakeSessionManagerClient* FakeSessionManagerClient() {
+  auto* fake_session_manager_client = FakeSessionManagerClient::Get();
   DCHECK(fake_session_manager_client);
   return fake_session_manager_client;
 }
@@ -649,7 +649,7 @@
     if (!command_line->HasSwitch(switches::kLoginProfile)) {
       command_line->AppendSwitchASCII(
           switches::kLoginProfile,
-          ash::BrowserContextHelper::kTestUserBrowserContextDirName);
+          BrowserContextHelper::kTestUserBrowserContextDirName);
     }
     LOG(WARNING)
         << "Running as stub user with profile dir: "
@@ -660,7 +660,7 @@
   CHECK(DBusThreadManager::IsInitialized());
 
   // Triggers the installation as earlier as possible.
-  ash::DocumentScannerInstaller::GetInstance()->TriggerInstall();
+  DocumentScannerInstaller::GetInstance()->TriggerInstall();
 
 #if !defined(USE_REAL_DBUS_CLIENTS)
   // USE_REAL_DBUS clients may be undefined even if the device is using real
@@ -870,7 +870,7 @@
       std::make_unique<policy::LockToSingleUserManager>();
 
   shortcut_mapping_pref_service_ =
-      std::make_unique<ash::ShortcutMappingPrefService>();
+      std::make_unique<ShortcutMappingPrefService>();
 
   // AccessibilityManager and SystemKeyEventListener use InputMethodManager.
   input_method::Initialize();
@@ -881,7 +881,7 @@
 
   // ProfileHelper has to be initialized after UserManager instance is created.
   ProfileHelper::Get()->Initialize();
-  signin_profile_handler_ = std::make_unique<ash::SigninProfileHandler>();
+  signin_profile_handler_ = std::make_unique<SigninProfileHandler>();
 
   // If kLoginUser is passed this indicates that user has already
   // logged in and we should behave accordingly.
@@ -1199,7 +1199,7 @@
     if (features::IsTrafficCountersEnabled()) {
       // Initialize the TrafficCountersHandler instance.
       traffic_counters_handler_ =
-          std::make_unique<ash::traffic_counters::TrafficCountersHandler>();
+          std::make_unique<traffic_counters::TrafficCountersHandler>();
       traffic_counters_handler_->Start();
     }
 
@@ -1376,8 +1376,8 @@
       MemoryMetrics::kDefaultPeriodInSeconds);
   memory_pressure_detail_->Start();
 
-  if (ash::memory::ZramWritebackController::IsSupportedAndEnabled()) {
-    zram_writeback_controller_ = ash::memory::ZramWritebackController::Create();
+  if (memory::ZramWritebackController::IsSupportedAndEnabled()) {
+    zram_writeback_controller_ = memory::ZramWritebackController::Create();
     zram_writeback_controller_->Start();
   }
 
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.h b/chrome/browser/ash/chrome_browser_main_parts_ash.h
index 0d478be..edffc7f 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.h
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.h
@@ -12,11 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "chrome/browser/ash/external_metrics.h"
-// TODO(https://crbug.com/1164001): remove and use forward declaration.
-#include "chrome/browser/ash/network_change_manager_client.h"
 #include "chrome/browser/ash/pcie_peripheral/ash_usb_detector.h"
-// TODO(https://crbug.com/1164001): remove and use forward declaration.
-#include "chrome/browser/ash/system_token_cert_db_initializer.h"
 #include "chrome/browser/ash/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
 #include "chrome/browser/chrome_browser_main_linux.h"
 #include "chrome/browser/memory/memory_kills_monitor.h"
@@ -60,6 +56,7 @@
 }  // namespace policy
 
 namespace ash {
+
 class AccessibilityEventRewriterDelegateImpl;
 class ArcKioskAppManager;
 class AudioSurveyHandler;
@@ -77,6 +74,7 @@
 class LoginScreenExtensionsStorageCleaner;
 class LowDiskNotification;
 class MultiCaptureNotification;
+class NetworkChangeManagerClient;
 class NetworkPrefStateObserver;
 class NetworkThrottlingObserver;
 class MemoryMetrics;
@@ -86,6 +84,7 @@
 class ShortcutMappingPrefService;
 class ShutdownPolicyForwarder;
 class SigninProfileHandler;
+class SystemTokenCertDBInitializer;
 class WebKioskAppManager;
 
 namespace cros_healthd::internal {
@@ -210,8 +209,7 @@
   std::unique_ptr<WebKioskAppManager> web_kiosk_app_manager_;
   std::unique_ptr<MultiCaptureNotification> multi_capture_notification_;
 
-  std::unique_ptr<ash::ShortcutMappingPrefService>
-      shortcut_mapping_pref_service_;
+  std::unique_ptr<ShortcutMappingPrefService> shortcut_mapping_pref_service_;
   std::unique_ptr<ChromeKeyboardControllerClient>
       chrome_keyboard_controller_client_;
 
@@ -257,7 +255,7 @@
   // early, this will be false during PostMainMessageLoopRun(), etc.
   // Used to prevent shutting down classes that were not initialized.
   bool pre_profile_init_called_ = false;
-  std::unique_ptr<ash::SigninProfileHandler> signin_profile_handler_;
+  std::unique_ptr<SigninProfileHandler> signin_profile_handler_;
 
   std::unique_ptr<policy::LockToSingleUserManager> lock_to_single_user_manager_;
   std::unique_ptr<WilcoDtcSupportdManager> wilco_dtc_supportd_manager_;
@@ -280,15 +278,14 @@
 
   std::unique_ptr<CameraGeneralSurveyHandler> camera_general_survey_handler_;
 
-  std::unique_ptr<ash::memory::ZramWritebackController>
-      zram_writeback_controller_;
+  std::unique_ptr<memory::ZramWritebackController> zram_writeback_controller_;
 
   // Only temporarily owned, will be null after PostCreateMainMessageLoop().
   // The Accessor is constructed before initialization of FeatureList and should
   // only be used by ChromeFeaturesServiceProvider.
   std::unique_ptr<base::FeatureList::Accessor> feature_list_accessor_;
 
-  std::unique_ptr<ash::traffic_counters::TrafficCountersHandler>
+  std::unique_ptr<traffic_counters::TrafficCountersHandler>
       traffic_counters_handler_;
 
   base::WeakPtrFactory<ChromeBrowserMainPartsAsh> weak_ptr_factory_{this};
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index 3304df2..8fdffb4 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -174,6 +174,8 @@
     "networking_private_ash.h",
     "parent_access_ash.cc",
     "parent_access_ash.h",
+    "persistent_forced_extension_keep_alive.cc",
+    "persistent_forced_extension_keep_alive.h",
     "policy_service_ash.cc",
     "policy_service_ash.h",
     "prefs_ash.cc",
@@ -318,6 +320,7 @@
     "//components/services/app_service/public/cpp:instance_update",
     "//components/session_manager/core",
     "//components/ukm:ukm",
+    "//components/user_prefs:user_prefs",
     "//components/version_info:channel",
     "//content/public/common",
     "//extensions/browser/api",
@@ -423,6 +426,7 @@
     "network_settings_translation_unittest.cc",
     "networking_attributes_ash_unittest.cc",
     "parent_access_ash_unittest.cc",
+    "persistent_forced_extension_keep_alive_unittest.cc",
     "prefs_ash_unittest.cc",
     "test_local_printer_ash.cc",
     "test_local_printer_ash.h",
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc
index a629409e..dee1a3de 100644
--- a/chrome/browser/ash/crosapi/browser_manager.cc
+++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -1660,4 +1660,19 @@
   g_disabled_for_testing = false;
 }
 
+BrowserManager::ScopedUnsetAllKeepAliveForTesting::
+    ScopedUnsetAllKeepAliveForTesting(BrowserManager* manager)
+    : manager_(manager) {
+  previous_keep_alive_features_ = std::move(manager_->keep_alive_features_);
+  manager_->keep_alive_features_.clear();
+  manager_->UpdateKeepAliveInBrowserIfNecessary(false);
+}
+
+BrowserManager::ScopedUnsetAllKeepAliveForTesting::
+    ~ScopedUnsetAllKeepAliveForTesting() {
+  manager_->keep_alive_features_ = std::move(previous_keep_alive_features_);
+  manager_->UpdateKeepAliveInBrowserIfNecessary(
+      !manager_->keep_alive_features_.empty());
+}
+
 }  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/browser_manager.h b/chrome/browser/ash/crosapi/browser_manager.h
index 173f0fc..74d17c7 100644
--- a/chrome/browser/ash/crosapi/browser_manager.h
+++ b/chrome/browser/ash/crosapi/browser_manager.h
@@ -77,6 +77,7 @@
 
 class BrowserLoader;
 class FilesAppLauncher;
+class PersistentForcedExtensionKeepAlive;
 class TestMojoConnectionManager;
 
 using browser_util::LacrosSelection;
@@ -479,6 +480,10 @@
   // Ash. Thus, session controller needs to keep Lacros alive to keep track of
   // smart card status.
   friend class ash::login::SecurityTokenSessionController;
+  // Registers a KeepAlive if there is a force-installed extension that should
+  // always be running.
+  friend class PersistentForcedExtensionKeepAlive;
+  friend class PersistentForcedExtensionKeepAliveTest;
 
   // Processes the action depending on the current state.
   // Ignoring a few exceptional cases, the logic is as follows:
@@ -499,6 +504,7 @@
     kApkWebAppService,
     kChromeApps,
     kExtensions,
+    kPersistentForcedExtension,
     kSmartCardSessionController,
   };
 
@@ -518,6 +524,17 @@
     Feature feature_;
   };
 
+  // De-registers any already existing KeepAlive features for testing.
+  class ScopedUnsetAllKeepAliveForTesting {
+   public:
+    explicit ScopedUnsetAllKeepAliveForTesting(BrowserManager* manager);
+    ~ScopedUnsetAllKeepAliveForTesting();
+
+   private:
+    BrowserManager* manager_;
+    std::set<BrowserManager::Feature> previous_keep_alive_features_;
+  };
+
   // Ash features that want Lacros to stay running in the background must be
   // marked as friends of this class so that lacros owners can audit usage.
   std::unique_ptr<ScopedKeepAlive> KeepAlive(Feature feature);
diff --git a/chrome/browser/ash/crosapi/keystore_service_ash.cc b/chrome/browser/ash/crosapi/keystore_service_ash.cc
index fef6138..035933f 100644
--- a/chrome/browser/ash/crosapi/keystore_service_ash.cc
+++ b/chrome/browser/ash/crosapi/keystore_service_ash.cc
@@ -669,7 +669,7 @@
           crosapi::mojom::KeystoreError::kUnsupportedAlgorithmType);
     }
   } else {
-    result_ptr->set_error(
+    result_ptr = mojom::GetPublicKeyResult::NewError(
         chromeos::platform_keys::StatusToKeystoreError(output.status));
   }
   std::move(callback).Run(std::move(result_ptr));
diff --git a/chrome/browser/ash/crosapi/keystore_service_ash_unittest.cc b/chrome/browser/ash/crosapi/keystore_service_ash_unittest.cc
index e6211b6c..ab04228 100644
--- a/chrome/browser/ash/crosapi/keystore_service_ash_unittest.cc
+++ b/chrome/browser/ash/crosapi/keystore_service_ash_unittest.cc
@@ -227,7 +227,7 @@
 
 //------------------------------------------------------------------------------
 
-TEST_F(KeystoreServiceAshTest, GenerateUserRsaKeySuccess) {
+TEST_F(KeystoreServiceAshTest, UserKeystoreRsaAlgoGenerateKeySuccess) {
   const unsigned int modulus_length = 2048;
 
   EXPECT_CALL(
@@ -245,7 +245,7 @@
   AssertBlobEq(observer.result.value(), GetPublicKeyBin());
 }
 
-TEST_F(KeystoreServiceAshTest, GenerateDeviceEcKeySuccess) {
+TEST_F(KeystoreServiceAshTest, DeviceKeystoreEcAlgoGenerateKeySuccess) {
   const std::string named_curve = "test_named_curve";
 
   EXPECT_CALL(platform_keys_service_,
@@ -261,7 +261,7 @@
   AssertBlobEq(observer.result.value(), GetPublicKeyBin());
 }
 
-TEST_F(KeystoreServiceAshTest, GenerateKeyFail) {
+TEST_F(KeystoreServiceAshTest, UserKeystoreUnsupportedEcCurveGenerateKeyFail) {
   EXPECT_CALL(platform_keys_service_, GenerateECKey)
       .WillOnce(RunOnceCallback<2>("", Status::kErrorInternal));
 
@@ -316,7 +316,26 @@
   AssertBlobEq(observer.result.value(), GetDataBin());
 }
 
-TEST_F(KeystoreServiceAshTest, SignFail) {
+TEST_F(KeystoreServiceAshTest, UsingkRsassaPkcs1V15NoneSignSuccess) {
+  EXPECT_CALL(platform_keys_service_,
+              SignRSAPKCS1Raw(absl::optional<TokenId>(TokenId::kSystem),
+                              GetDataStr(), GetPublicKeyStr(),
+                              /*callback=*/_))
+      .WillOnce(RunOnceCallback<3>(GetDataStr(), Status::kSuccess));
+
+  mojom::KeystoreSigningScheme sign_scheme =
+      mojom::KeystoreSigningScheme::kRsassaPkcs1V15None;
+  CallbackObserver<mojom::KeystoreBinaryResultPtr> observer;
+
+  keystore_service_.Sign(
+      /*is_keystore_provided=*/true, mojom::KeystoreType::kDevice,
+      GetPublicKeyBin(), sign_scheme, GetDataBin(), observer.GetCallback());
+
+  ASSERT_TRUE(observer.result.has_value());
+  AssertBlobEq(observer.result.value(), GetDataBin());
+}
+
+TEST_F(KeystoreServiceAshTest, KeyNotAllowedSignFail) {
   EXPECT_CALL(platform_keys_service_, SignECDSADigest)
       .WillOnce(RunOnceCallback<4>("", Status::kErrorKeyNotAllowedForSigning));
 
@@ -331,6 +350,21 @@
                 mojom::KeystoreError::kKeyNotAllowedForSigning);
 }
 
+TEST_F(KeystoreServiceAshTest, UnknownSignSchemeSignFail) {
+  CallbackObserver<mojom::KeystoreBinaryResultPtr> observer;
+  mojom::KeystoreSigningScheme unknown_sign_scheme =
+      mojom::KeystoreSigningScheme::kUnknown;
+
+  keystore_service_.Sign(
+      /*is_keystore_provided=*/true, mojom::KeystoreType::kDevice,
+      GetPublicKeyBin(), unknown_sign_scheme, GetDataBin(),
+      observer.GetCallback());
+
+  ASSERT_TRUE(observer.result.has_value());
+  AssertErrorEq(observer.result.value(),
+                mojom::KeystoreError::kUnsupportedAlgorithmType);
+}
+
 //------------------------------------------------------------------------------
 
 TEST_F(KeystoreServiceAshTest, RemoveKeySuccess) {
@@ -497,7 +531,7 @@
   EXPECT_EQ(params->public_exponent, (std::vector<uint8_t>{1, 0, 1}));
 }
 
-TEST_F(KeystoreServiceAshTest, GetPublicKeyFail) {
+TEST_F(KeystoreServiceAshTest, WrongAlgoGetPublicKeyFail) {
   const std::vector<uint8_t> cert_bin =
       CertToBlob(GetCertificateList()->front());
 
@@ -511,6 +545,20 @@
                 mojom::KeystoreError::kAlgorithmNotPermittedByCertificate);
 }
 
+TEST_F(KeystoreServiceAshTest, BadCertificateGetPublicKeyFail) {
+  // Using some random sequence as certificate
+  const std::vector<uint8_t> bad_cert_bin = {10, 11, 12, 13, 14, 15};
+  CallbackObserver<mojom::GetPublicKeyResultPtr> observer;
+
+  keystore_service_.GetPublicKey(
+      bad_cert_bin, mojom::KeystoreSigningAlgorithmName::kRsassaPkcs115,
+      observer.GetCallback());
+
+  ASSERT_TRUE(observer.result.has_value());
+  AssertErrorEq(observer.result.value(),
+                mojom::KeystoreError::kCertificateInvalid);
+}
+
 //------------------------------------------------------------------------------
 
 TEST_F(KeystoreServiceAshTest, GetKeyStoresEmptySuccess) {
@@ -912,6 +960,22 @@
             challenge_result.GetErrorMessage());
 }
 
+TEST_F(KeystoreServiceAshTest, WrongKeystoreTypeChallengeFail) {
+  CallbackObserver<mojom::ChallengeAttestationOnlyKeystoreResultPtr> observer;
+
+  auto wrong_keystore_type = static_cast<mojom::KeystoreType>(3);
+  keystore_service_.ChallengeAttestationOnlyKeystore(
+      wrong_keystore_type, /*challenge=*/GetDataBin(),
+      /*migrate=*/false, mojom::KeystoreSigningAlgorithmName::kRsassaPkcs115,
+      observer.GetCallback());
+
+  ASSERT_TRUE(observer.result.has_value());
+  ASSERT_TRUE(observer.result.value()->is_error_message());
+  EXPECT_EQ(observer.result.value()->get_error_message(),
+            chromeos::platform_keys::KeystoreErrorToString(
+                mojom::KeystoreError::kUnsupportedKeystoreType));
+}
+
 //------------------------------------------------------------------------------
 
 // Tests for deprecated methods.
diff --git a/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc b/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc
index 6d9e6ca..0ba8103 100644
--- a/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc
+++ b/chrome/browser/ash/crosapi/local_printer_ash_unittest.cc
@@ -63,7 +63,6 @@
 
 using ::chromeos::Printer;
 using ::chromeos::PrinterClass;
-using ::chromeos::PrinterConfigurer;
 
 namespace printing {
 
diff --git a/chrome/browser/ash/crosapi/login_ash.cc b/chrome/browser/ash/crosapi/login_ash.cc
index 273439c..4e082a6 100644
--- a/chrome/browser/ash/crosapi/login_ash.cc
+++ b/chrome/browser/ash/crosapi/login_ash.cc
@@ -60,8 +60,8 @@
       context.SetCanLockManagedGuestSession(true);
     }
 
-    chromeos::ExistingUserController* existing_user_controller =
-        chromeos::ExistingUserController::current_controller();
+    auto* existing_user_controller =
+        ash::ExistingUserController::current_controller();
     existing_user_controller->Login(context, ash::SigninSpecifics());
     std::move(callback).Run(absl::nullopt);
     return;
@@ -330,8 +330,8 @@
     return extensions::login_api_errors::kAlreadyActiveSession;
   }
 
-  chromeos::ExistingUserController* existing_user_controller =
-      chromeos::ExistingUserController::current_controller();
+  auto* existing_user_controller =
+      ash::ExistingUserController::current_controller();
   if (existing_user_controller->IsSigninInProgress())
     return extensions::login_api_errors::kAnotherLoginAttemptInProgress;
 
diff --git a/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive.cc b/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive.cc
new file mode 100644
index 0000000..fc0e35f
--- /dev/null
+++ b/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive.cc
@@ -0,0 +1,127 @@
+// 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/ash/crosapi/persistent_forced_extension_keep_alive.h"
+
+#include "base/no_destructor.h"
+#include "chrome/browser/ash/crosapi/browser_manager.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/pref_names.h"
+#include "extensions/common/extension_id.h"
+#include "extensions/common/features/behavior_feature.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/features/feature_provider.h"
+#include "extensions/common/hashed_extension_id.h"
+
+namespace {
+
+bool ShouldEnableKeepAlive(const base::Value::Dict& extension_install_list) {
+  // Lacros should be kept alive if the Imprivata in-session extension is
+  // installed by admin policy.
+  const extensions::Feature* feature =
+      extensions::FeatureProvider::GetBehaviorFeature(
+          extensions::behavior_feature::kImprivataInSessionExtension);
+  DCHECK(feature);
+
+  for (auto entry : extension_install_list) {
+    const extensions::ExtensionId& extension_id = entry.first;
+    const extensions::HashedExtensionId& hashed_extension_id =
+        extensions::HashedExtensionId(extension_id);
+
+    if (feature->IsIdInAllowlist(hashed_extension_id))
+      return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+namespace crosapi {
+
+PersistentForcedExtensionKeepAlive::PersistentForcedExtensionKeepAlive(
+    PrefService* user_prefs) {
+  DCHECK(user_prefs);
+
+  pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
+  pref_change_registrar_->Init(user_prefs);
+  pref_change_registrar_->Add(
+      extensions::pref_names::kInstallForceList,
+      base::BindRepeating(&PersistentForcedExtensionKeepAlive::UpdateKeepAlive,
+                          weak_factory_.GetWeakPtr()));
+
+  UpdateKeepAlive();
+}
+
+PersistentForcedExtensionKeepAlive::~PersistentForcedExtensionKeepAlive() =
+    default;
+
+void PersistentForcedExtensionKeepAlive::Shutdown() {
+  keep_alive_.reset();
+  weak_factory_.InvalidateWeakPtrs();
+}
+
+void PersistentForcedExtensionKeepAlive::UpdateKeepAlive() {
+  DCHECK(pref_change_registrar_);
+  DCHECK(pref_change_registrar_->prefs());
+
+  const base::Value::Dict& extension_install_list =
+      pref_change_registrar_->prefs()->GetDict(
+          extensions::pref_names::kInstallForceList);
+
+  if (!ShouldEnableKeepAlive(extension_install_list)) {
+    keep_alive_.reset();
+    return;
+  }
+  if (!keep_alive_) {
+    keep_alive_ = BrowserManager::Get()->KeepAlive(
+        BrowserManager::Feature::kPersistentForcedExtension);
+  }
+}
+
+// static
+PersistentForcedExtensionKeepAliveFactory*
+PersistentForcedExtensionKeepAliveFactory::GetInstance() {
+  static base::NoDestructor<PersistentForcedExtensionKeepAliveFactory> instance;
+  return instance.get();
+}
+
+PersistentForcedExtensionKeepAliveFactory::
+    PersistentForcedExtensionKeepAliveFactory()
+    : BrowserContextKeyedServiceFactory(
+          "PersistentForcedExtensionKeepAlive",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+PersistentForcedExtensionKeepAliveFactory::
+    ~PersistentForcedExtensionKeepAliveFactory() = default;
+
+KeyedService*
+PersistentForcedExtensionKeepAliveFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  if (!browser_util::IsLacrosEnabled())
+    return nullptr;
+  Profile* profile = Profile::FromBrowserContext(context);
+  if (!profile)
+    return nullptr;
+  if (ash::ProfileHelper::IsSigninProfile(profile)) {
+    // Does not have to be registered on the sign-in profile.
+    return nullptr;
+  }
+  return new PersistentForcedExtensionKeepAlive(
+      user_prefs::UserPrefs::Get(context));
+}
+
+bool PersistentForcedExtensionKeepAliveFactory::
+    ServiceIsCreatedWithBrowserContext() const {
+  // Service is created in the background as soon as the BrowserContext has been
+  // brought up.
+  return true;
+}
+
+}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive.h b/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive.h
new file mode 100644
index 0000000..8ef9ed78
--- /dev/null
+++ b/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive.h
@@ -0,0 +1,68 @@
+// 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_ASH_CROSAPI_PERSISTENT_FORCED_EXTENSION_KEEP_ALIVE_H_
+#define CHROME_BROWSER_ASH_CROSAPI_PERSISTENT_FORCED_EXTENSION_KEEP_ALIVE_H_
+
+#include "base/no_destructor.h"
+#include "chrome/browser/ash/crosapi/browser_manager.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/prefs/pref_service.h"
+
+class PrefChangeRegistrar;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace crosapi {
+
+// Registers a KeepAlive instance in Lacros if there is an extension
+// force-installed by admin policy that should always be running.
+class PersistentForcedExtensionKeepAlive final : public KeyedService {
+ public:
+  explicit PersistentForcedExtensionKeepAlive(PrefService* user_prefs);
+  PersistentForcedExtensionKeepAlive(
+      const PersistentForcedExtensionKeepAlive&) = delete;
+  PersistentForcedExtensionKeepAlive& operator=(
+      const PersistentForcedExtensionKeepAlive&) = delete;
+  ~PersistentForcedExtensionKeepAlive() override;
+
+  // KeyedService:
+  void Shutdown() override;
+
+ private:
+  // Reads the `kInstallForceList` pref value and, if required, updates
+  // keep_alive_. Called when the user prefs changed.
+  void UpdateKeepAlive();
+
+  std::unique_ptr<BrowserManager::ScopedKeepAlive> keep_alive_;
+  std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
+
+  // Must be the last member.
+  base::WeakPtrFactory<PersistentForcedExtensionKeepAlive> weak_factory_{this};
+};
+
+// Factory for the `PersistentForcedExtensionKeepAlive` KeyedService.
+class PersistentForcedExtensionKeepAliveFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static PersistentForcedExtensionKeepAliveFactory* GetInstance();
+
+ private:
+  friend class base::NoDestructor<PersistentForcedExtensionKeepAliveFactory>;
+
+  PersistentForcedExtensionKeepAliveFactory();
+  ~PersistentForcedExtensionKeepAliveFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  bool ServiceIsCreatedWithBrowserContext() const override;
+};
+
+}  // namespace crosapi
+
+#endif  // CHROME_BROWSER_ASH_CROSAPI_PERSISTENT_FORCED_EXTENSION_KEEP_ALIVE_H_
diff --git a/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive_unittest.cc b/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive_unittest.cc
new file mode 100644
index 0000000..b006502
--- /dev/null
+++ b/chrome/browser/ash/crosapi/persistent_forced_extension_keep_alive_unittest.cc
@@ -0,0 +1,121 @@
+// 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/ash/crosapi/persistent_forced_extension_keep_alive.h"
+
+#include "base/auto_reset.h"
+#include "chrome/browser/ash/crosapi/browser_manager.h"
+#include "chrome/browser/ash/crosapi/fake_browser_manager.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/test/browser_task_environment.h"
+#include "extensions/browser/pref_names.h"
+#include "extensions/common/extension_builder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kAllowedExtensionId[] = "baobpecgllpajfeojepgedjdlnlfffde";
+const char kNotAllowedExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+constexpr char kUserEmail[] = "user@email.com";
+
+}  // namespace
+
+namespace crosapi {
+
+class PersistentForcedExtensionKeepAliveTest : public testing::Test {
+ public:
+  PersistentForcedExtensionKeepAliveTest()
+      : browser_manager_(std::make_unique<FakeBrowserManager>()) {}
+
+  PersistentForcedExtensionKeepAliveTest(
+      const PersistentForcedExtensionKeepAliveTest&) = delete;
+  PersistentForcedExtensionKeepAliveTest& operator=(
+      const PersistentForcedExtensionKeepAliveTest&) = delete;
+
+  ~PersistentForcedExtensionKeepAliveTest() override = default;
+
+  void SetUp() override {
+    ASSERT_TRUE(browser_util::IsLacrosEnabled());
+
+    profile_manager_ = std::make_unique<TestingProfileManager>(
+        TestingBrowserProcess::GetGlobal());
+    ASSERT_TRUE(profile_manager_->SetUp());
+
+    scoped_unset_all_keep_alive_ =
+        std::make_unique<BrowserManager::ScopedUnsetAllKeepAliveForTesting>(
+            BrowserManager::Get());
+
+    CreateTestingProfile();
+  }
+
+  void TearDown() override {
+    profile_manager_->DeleteAllTestingProfiles();
+    profile_manager_.reset();
+  }
+
+  void CreateTestingProfile() {
+    profile_ = profile_manager_->CreateTestingProfile(kUserEmail);
+  }
+
+  void SetInstallForceList(const std::string& extension_id) {
+    std::unique_ptr<base::Value> dict =
+        extensions::DictionaryBuilder()
+            .Set(extension_id, extensions::DictionaryBuilder().Build())
+            .Build();
+    profile_->GetPrefs()->Set(extensions::pref_names::kInstallForceList,
+                              std::move(*dict));
+  }
+
+  FakeBrowserManager& browser_manager() { return *browser_manager_; }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+
+  base::AutoReset<bool> set_lacros_enabled_ =
+      browser_util::SetLacrosEnabledForTest(true);
+
+  std::unique_ptr<FakeBrowserManager> browser_manager_;
+  std::unique_ptr<TestingProfileManager> profile_manager_;
+
+  std::unique_ptr<BrowserManager::ScopedUnsetAllKeepAliveForTesting>
+      scoped_unset_all_keep_alive_;
+
+  TestingProfile* profile_;
+};
+
+// Test that KeepAlive is registered on session start if an extension that
+// requires Lacros to be running is force-installed.
+TEST_F(PersistentForcedExtensionKeepAliveTest, StartKeepAliveIfAllowlisted) {
+  SetInstallForceList(kAllowedExtensionId);
+  EXPECT_TRUE(browser_manager().IsKeepAliveEnabled());
+}
+
+// Test that KeepAlive is not registered if no forced extension requires Lacros
+// to be kept alive.
+TEST_F(PersistentForcedExtensionKeepAliveTest,
+       DontStartKeepAliveIfExtensionNotAllowlisted) {
+  SetInstallForceList(kNotAllowedExtensionId);
+  EXPECT_FALSE(browser_manager().IsKeepAliveEnabled());
+}
+
+// Test that KeepAlive is not registered if there are no force-installed
+// extensions.
+TEST_F(PersistentForcedExtensionKeepAliveTest, DontStartKeepAliveIfUnset) {
+  EXPECT_FALSE(browser_manager().IsKeepAliveEnabled());
+}
+
+// Test that KeepAlive reacts to pref value changes.
+TEST_F(PersistentForcedExtensionKeepAliveTest,
+       UpdateKeepAliveOnPrefValueChanges) {
+  SetInstallForceList(kAllowedExtensionId);
+  EXPECT_TRUE(browser_manager().IsKeepAliveEnabled());
+
+  SetInstallForceList(kNotAllowedExtensionId);
+  EXPECT_FALSE(browser_manager().IsKeepAliveEnabled());
+}
+
+}  // namespace crosapi
diff --git a/chrome/browser/ash/cryptauth/client_app_metadata_provider_service_factory.h b/chrome/browser/ash/cryptauth/client_app_metadata_provider_service_factory.h
index 2527f16..a61d1d8d 100644
--- a/chrome/browser/ash/cryptauth/client_app_metadata_provider_service_factory.h
+++ b/chrome/browser/ash/cryptauth/client_app_metadata_provider_service_factory.h
@@ -40,9 +40,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the migration is finished.
-namespace chromeos {
-using ::ash::ClientAppMetadataProviderServiceFactory;
-}
-
 #endif  // CHROME_BROWSER_ASH_CRYPTAUTH_CLIENT_APP_METADATA_PROVIDER_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ash/cryptauth/gcm_device_info_provider_impl.h b/chrome/browser/ash/cryptauth/gcm_device_info_provider_impl.h
index c464082f..16f0aaf 100644
--- a/chrome/browser/ash/cryptauth/gcm_device_info_provider_impl.h
+++ b/chrome/browser/ash/cryptauth/gcm_device_info_provider_impl.h
@@ -31,9 +31,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the migration is finished.
-namespace chromeos {
-using ::ash::GcmDeviceInfoProviderImpl;
-}
-
 #endif  // CHROME_BROWSER_ASH_CRYPTAUTH_GCM_DEVICE_INFO_PROVIDER_IMPL_H_
diff --git a/chrome/browser/ash/customization/customization_document.h b/chrome/browser/ash/customization/customization_document.h
index d2da5250..2be023a 100644
--- a/chrome/browser/ash/customization/customization_document.h
+++ b/chrome/browser/ash/customization/customization_document.h
@@ -331,10 +331,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-using ::ash::ServicesCustomizationDocument;
-using ::ash::StartupCustomizationDocument;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_CUSTOMIZATION_CUSTOMIZATION_DOCUMENT_H_
diff --git a/chrome/browser/ash/customization/customization_document_browsertest.cc b/chrome/browser/ash/customization/customization_document_browsertest.cc
index ad9d694a..ca8d6b8 100644
--- a/chrome/browser/ash/customization/customization_document_browsertest.cc
+++ b/chrome/browser/ash/customization/customization_document_browsertest.cc
@@ -22,13 +22,13 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
-using ash::locale_util::LanguageSwitchResult;
-using ash::locale_util::SwitchLanguageCallback;
-
 namespace ash {
 
 namespace {
 
+using locale_util::LanguageSwitchResult;
+using locale_util::SwitchLanguageCallback;
+
 class LanguageSwitchedWaiter {
  public:
   explicit LanguageSwitchedWaiter(SwitchLanguageCallback callback)
diff --git a/chrome/browser/ash/customization/customization_wallpaper_downloader_browsertest.cc b/chrome/browser/ash/customization/customization_wallpaper_downloader_browsertest.cc
index e2b4b13..4bedfc43 100644
--- a/chrome/browser/ash/customization/customization_wallpaper_downloader_browsertest.cc
+++ b/chrome/browser/ash/customization/customization_wallpaper_downloader_browsertest.cc
@@ -119,7 +119,7 @@
   return true;
 }
 
-class TestWallpaperObserver : public ash::WallpaperControllerObserver {
+class TestWallpaperObserver : public WallpaperControllerObserver {
  public:
   TestWallpaperObserver() {
     WallpaperControllerClientImpl::Get()->AddObserver(this);
@@ -132,7 +132,7 @@
     WallpaperControllerClientImpl::Get()->RemoveObserver(this);
   }
 
-  // ash::WallpaperControllerObserver:
+  // WallpaperControllerObserver:
   void OnWallpaperChanged() override {
     finished_ = true;
     base::RunLoop::QuitCurrentWhenIdleDeprecated();
diff --git a/chrome/browser/ash/customization/customization_wallpaper_util.cc b/chrome/browser/ash/customization/customization_wallpaper_util.cc
index 899aa67..90c0b621 100644
--- a/chrome/browser/ash/customization/customization_wallpaper_util.cc
+++ b/chrome/browser/ash/customization/customization_wallpaper_util.cc
@@ -57,14 +57,14 @@
     gfx::ImageSkia image,
     const base::FilePath& resized_small_path,
     const base::FilePath& resized_large_path) {
-  return SaveResizedWallpaper(image,
-                              gfx::Size(ash::kSmallWallpaperMaxWidth,
-                                        ash::kSmallWallpaperMaxHeight),
-                              resized_small_path) &&
-         SaveResizedWallpaper(image,
-                              gfx::Size(ash::kLargeWallpaperMaxWidth,
-                                        ash::kLargeWallpaperMaxHeight),
-                              resized_large_path);
+  return SaveResizedWallpaper(
+             image,
+             gfx::Size(kSmallWallpaperMaxWidth, kSmallWallpaperMaxHeight),
+             resized_small_path) &&
+         SaveResizedWallpaper(
+             image,
+             gfx::Size(kLargeWallpaperMaxWidth, kLargeWallpaperMaxHeight),
+             resized_large_path);
 }
 
 // Checks the result of |ResizeAndSaveCustomizedDefaultWallpaper| and sends
diff --git a/chrome/browser/ash/dbus/ash_dbus_helper.cc b/chrome/browser/ash/dbus/ash_dbus_helper.cc
index 5371b11..c60fac7 100644
--- a/chrome/browser/ash/dbus/ash_dbus_helper.cc
+++ b/chrome/browser/ash/dbus/ash_dbus_helper.cc
@@ -207,7 +207,7 @@
   // Initialize the device settings service so that we'll take actions per
   // signals sent from the session manager. This needs to happen before
   // g_browser_process initializes BrowserPolicyConnector.
-  chromeos::DeviceSettingsService::Initialize();
+  DeviceSettingsService::Initialize();
   InstallAttributes::Initialize();
 }
 
@@ -237,16 +237,16 @@
     InitializeDBusClient<CfmHotlineClient>(bus);
   }
 #endif
-  if (ash::shimless_rma::IsShimlessRmaAllowed()) {
+  if (shimless_rma::IsShimlessRmaAllowed()) {
     InitializeDBusClient<RmadClient>(bus);
   }
-  if (ash::features::IsRgbKeyboardEnabled()) {
+  if (features::IsRgbKeyboardEnabled()) {
     InitializeDBusClient<RgbkbdClient>(bus);
   }
-  InitializeDBusClient<chromeos::WilcoDtcSupportdClient>(bus);
+  InitializeDBusClient<WilcoDtcSupportdClient>(bus);
 
-  if (ash::features::IsSnoopingProtectionEnabled() ||
-      ash::features::IsQuickDimEnabled()) {
+  if (features::IsSnoopingProtectionEnabled() ||
+      features::IsQuickDimEnabled()) {
     InitializeDBusClient<HumanPresenceDBusClient>(bus);
   }
 }
@@ -254,11 +254,11 @@
 void ShutdownDBus() {
   // Feature list-dependent D-Bus clients are shut down first because we try to
   // shut down in reverse order of initialization (in case of dependencies).
-  if (ash::features::IsSnoopingProtectionEnabled() ||
-      ash::features::IsQuickDimEnabled()) {
+  if (features::IsSnoopingProtectionEnabled() ||
+      features::IsQuickDimEnabled()) {
     HumanPresenceDBusClient::Shutdown();
   }
-  chromeos::WilcoDtcSupportdClient::Shutdown();
+  WilcoDtcSupportdClient::Shutdown();
 #if BUILDFLAG(PLATFORM_CFM)
   if (base::FeatureList::IsEnabled(cfm::features::kMojoServices)) {
     CfmHotlineClient::Shutdown();
@@ -287,10 +287,10 @@
   SeneschalClient::Shutdown();
   RuntimeProbeClient::Shutdown();
   ResourcedClient::Shutdown();
-  if (ash::features::IsRgbKeyboardEnabled()) {
+  if (features::IsRgbKeyboardEnabled()) {
     RgbkbdClient::Shutdown();
   }
-  if (ash::shimless_rma::IsShimlessRmaAllowed()) {
+  if (shimless_rma::IsShimlessRmaAllowed()) {
     RmadClient::Shutdown();
   }
   chromeos::PowerManagerClient::Shutdown();
diff --git a/chrome/browser/ash/dbus/chrome_features_service_provider.cc b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
index 3f64e48..f3db9d6 100644
--- a/chrome/browser/ash/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
@@ -31,6 +31,8 @@
 #include "dbus/message.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
+namespace ash {
+
 namespace {
 
 // A prefix to apply to all features which Chrome OS platform-side code wishes
@@ -74,11 +76,10 @@
     return ProfileManager::GetActiveUserProfile();
 
   return g_browser_process->profile_manager()->GetProfileByPath(
-      ash::ProfileHelper::GetProfilePathByUserIdHash(user_id_hash));
+      ProfileHelper::GetProfilePathByUserIdHash(user_id_hash));
 }
-}  // namespace
 
-namespace ash {
+}  // namespace
 
 ChromeFeaturesServiceProvider::ChromeFeaturesServiceProvider(
     std::unique_ptr<base::FeatureList::Accessor> feature_list_accessor)
diff --git a/chrome/browser/ash/dbus/chrome_features_service_provider.h b/chrome/browser/ash/dbus/chrome_features_service_provider.h
index 8b20c46..72e8c54 100644
--- a/chrome/browser/ash/dbus/chrome_features_service_provider.h
+++ b/chrome/browser/ash/dbus/chrome_features_service_provider.h
@@ -108,9 +108,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::ChromeFeaturesServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_CHROME_FEATURES_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/component_updater_service_provider.h b/chrome/browser/ash/dbus/component_updater_service_provider.h
index dfc72aed..d08b78a4 100644
--- a/chrome/browser/ash/dbus/component_updater_service_provider.h
+++ b/chrome/browser/ash/dbus/component_updater_service_provider.h
@@ -117,9 +117,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::ComponentUpdaterServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_COMPONENT_UPDATER_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/cryptohome_key_delegate_service_provider.h b/chrome/browser/ash/dbus/cryptohome_key_delegate_service_provider.h
index a0f7c39..ce24c267 100644
--- a/chrome/browser/ash/dbus/cryptohome_key_delegate_service_provider.h
+++ b/chrome/browser/ash/dbus/cryptohome_key_delegate_service_provider.h
@@ -50,9 +50,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::CryptohomeKeyDelegateServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_CRYPTOHOME_KEY_DELEGATE_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/dlp_files_policy_service_provider.h b/chrome/browser/ash/dbus/dlp_files_policy_service_provider.h
index 090a6b7..eb603e2 100644
--- a/chrome/browser/ash/dbus/dlp_files_policy_service_provider.h
+++ b/chrome/browser/ash/dbus/dlp_files_policy_service_provider.h
@@ -59,9 +59,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::DlpFilesPolicyServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_DLP_FILES_POLICY_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/dlp_files_policy_service_provider_unittest.cc b/chrome/browser/ash/dbus/dlp_files_policy_service_provider_unittest.cc
index 1b087341..25471f7d 100644
--- a/chrome/browser/ash/dbus/dlp_files_policy_service_provider_unittest.cc
+++ b/chrome/browser/ash/dbus/dlp_files_policy_service_provider_unittest.cc
@@ -22,12 +22,14 @@
 namespace ash {
 
 namespace {
+
 constexpr char kEmailId[] = "test@example.com";
 constexpr char kGaiaId[] = "12345";
 
 constexpr char kExampleUrl[] = "https://example.com";
 constexpr ino_t kInode = 0;
 constexpr char kFilePath[] = "test.txt";
+
 }  // namespace
 
 class DlpFilesPolicyServiceProviderTest
@@ -35,7 +37,7 @@
  protected:
   DlpFilesPolicyServiceProviderTest()
       : profile_(std::make_unique<TestingProfile>()),
-        user_manager_(new ash::FakeChromeUserManager()),
+        user_manager_(new FakeChromeUserManager()),
         scoped_user_manager_(base::WrapUnique(user_manager_)),
         dlp_policy_service_(std::make_unique<DlpFilesPolicyServiceProvider>()) {
   }
@@ -116,7 +118,7 @@
   policy::MockDlpRulesManager* mock_rules_manager_ = nullptr;
 
   const std::unique_ptr<TestingProfile> profile_;
-  ash::FakeChromeUserManager* user_manager_;
+  FakeChromeUserManager* user_manager_;
   user_manager::ScopedUserManager scoped_user_manager_;
 
   std::unique_ptr<DlpFilesPolicyServiceProvider> dlp_policy_service_;
diff --git a/chrome/browser/ash/dbus/drive_file_stream_service_provider.h b/chrome/browser/ash/dbus/drive_file_stream_service_provider.h
index d19376b5..68dcb814 100644
--- a/chrome/browser/ash/dbus/drive_file_stream_service_provider.h
+++ b/chrome/browser/ash/dbus/drive_file_stream_service_provider.h
@@ -52,9 +52,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::DriveFileStreamServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_DRIVE_FILE_STREAM_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/encrypted_reporting_service_provider.h b/chrome/browser/ash/dbus/encrypted_reporting_service_provider.h
index c9af2a36..b99ab81 100644
--- a/chrome/browser/ash/dbus/encrypted_reporting_service_provider.h
+++ b/chrome/browser/ash/dbus/encrypted_reporting_service_provider.h
@@ -96,9 +96,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::EncryptedReportingServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_ENCRYPTED_REPORTING_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/kiosk_info_service_provider.h b/chrome/browser/ash/dbus/kiosk_info_service_provider.h
index fa9549d..048187d 100644
--- a/chrome/browser/ash/dbus/kiosk_info_service_provider.h
+++ b/chrome/browser/ash/dbus/kiosk_info_service_provider.h
@@ -49,9 +49,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::KioskInfoService;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_KIOSK_INFO_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/libvda_service_provider.h b/chrome/browser/ash/dbus/libvda_service_provider.h
index 6a6f879e..6e4063c 100644
--- a/chrome/browser/ash/dbus/libvda_service_provider.h
+++ b/chrome/browser/ash/dbus/libvda_service_provider.h
@@ -58,9 +58,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::LibvdaServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_LIBVDA_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/lock_to_single_user_service_provider.h b/chrome/browser/ash/dbus/lock_to_single_user_service_provider.h
index 869a5329e..f3a17a4 100644
--- a/chrome/browser/ash/dbus/lock_to_single_user_service_provider.h
+++ b/chrome/browser/ash/dbus/lock_to_single_user_service_provider.h
@@ -55,9 +55,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::LockToSingleUserServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_LOCK_TO_SINGLE_USER_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/machine_learning_decision_service_provider.h b/chrome/browser/ash/dbus/machine_learning_decision_service_provider.h
index 52e60593..fa9e4d6 100644
--- a/chrome/browser/ash/dbus/machine_learning_decision_service_provider.h
+++ b/chrome/browser/ash/dbus/machine_learning_decision_service_provider.h
@@ -18,6 +18,7 @@
 }  // namespace dbus
 
 namespace ash {
+
 namespace power {
 namespace ml {
 class UserActivityController;
@@ -82,9 +83,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::MachineLearningDecisionServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_MACHINE_LEARNING_DECISION_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/metrics_event_service_provider.h b/chrome/browser/ash/dbus/metrics_event_service_provider.h
index c3b6ea8d..e2e9060 100644
--- a/chrome/browser/ash/dbus/metrics_event_service_provider.h
+++ b/chrome/browser/ash/dbus/metrics_event_service_provider.h
@@ -46,9 +46,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::MetricsEventServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_METRICS_EVENT_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/mojo_connection_service_provider.h b/chrome/browser/ash/dbus/mojo_connection_service_provider.h
index 155c1a33..5c8e97c 100644
--- a/chrome/browser/ash/dbus/mojo_connection_service_provider.h
+++ b/chrome/browser/ash/dbus/mojo_connection_service_provider.h
@@ -88,9 +88,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::MojoConnectionServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_MOJO_CONNECTION_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/printers_service_provider.h b/chrome/browser/ash/dbus/printers_service_provider.h
index 227a27f..bd581ec 100644
--- a/chrome/browser/ash/dbus/printers_service_provider.h
+++ b/chrome/browser/ash/dbus/printers_service_provider.h
@@ -50,9 +50,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::PrintersServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_PRINTERS_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/proxy_resolution_service_provider.cc b/chrome/browser/ash/dbus/proxy_resolution_service_provider.cc
index 73b0958..721f324 100644
--- a/chrome/browser/ash/dbus/proxy_resolution_service_provider.cc
+++ b/chrome/browser/ash/dbus/proxy_resolution_service_provider.cc
@@ -97,7 +97,7 @@
   // trough the same Chrome proxy resolution service to connect to the
   // remote proxy server. The availability of this feature is controlled by the
   // |SystemProxySettings| policy and the feature flag
-  // `ash::features::kSystemProxyForSystemServices`.
+  // `features::kSystemProxyForSystemServices`.
   void AppendSystemProxyIfActive(std::string* pac_proxy_list) {
     SystemProxyManager* system_proxy_manager = SystemProxyManager::Get();
     // |system_proxy_manager| may be missing in tests.
diff --git a/chrome/browser/ash/dbus/proxy_resolution_service_provider.h b/chrome/browser/ash/dbus/proxy_resolution_service_provider.h
index 67c1727..235005e 100644
--- a/chrome/browser/ash/dbus/proxy_resolution_service_provider.h
+++ b/chrome/browser/ash/dbus/proxy_resolution_service_provider.h
@@ -134,9 +134,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::ProxyResolutionServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_PROXY_RESOLUTION_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/proxy_resolution_service_provider_unittest.cc b/chrome/browser/ash/dbus/proxy_resolution_service_provider_unittest.cc
index 3fdf338..d4710f989 100644
--- a/chrome/browser/ash/dbus/proxy_resolution_service_provider_unittest.cc
+++ b/chrome/browser/ash/dbus/proxy_resolution_service_provider_unittest.cc
@@ -219,7 +219,7 @@
 }
 
 // Tests the behaviour of system-proxy when enabled via the feature flag
-// `ash::features::kSystemProxyForSystemServices` and via the device policy
+// `features::kSystemProxyForSystemServices` and via the device policy
 // SystemProxySettings.
 class ProxyResolutionServiceWithSystemProxyTest
     : public ProxyResolutionServiceProviderTest {
@@ -232,7 +232,7 @@
   // testing::Test
   void SetUp() override {
     scoped_feature_list_.InitAndEnableFeature(
-        ash::features::kSystemProxyForSystemServices);
+        features::kSystemProxyForSystemServices);
     ProxyResolutionServiceProviderTest::SetUp();
 
     SystemProxyClient::InitializeFake();
diff --git a/chrome/browser/ash/dbus/screen_lock_service_provider.h b/chrome/browser/ash/dbus/screen_lock_service_provider.h
index 74abf19..5136108 100644
--- a/chrome/browser/ash/dbus/screen_lock_service_provider.h
+++ b/chrome/browser/ash/dbus/screen_lock_service_provider.h
@@ -52,9 +52,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::ScreenLockServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_SCREEN_LOCK_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/smb_fs_service_provider.h b/chrome/browser/ash/dbus/smb_fs_service_provider.h
index e32227c8..c883498 100644
--- a/chrome/browser/ash/dbus/smb_fs_service_provider.h
+++ b/chrome/browser/ash/dbus/smb_fs_service_provider.h
@@ -43,9 +43,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::SmbFsServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_SMB_FS_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/virtual_file_request_service_provider.h b/chrome/browser/ash/dbus/virtual_file_request_service_provider.h
index 71a43aa..1687783 100644
--- a/chrome/browser/ash/dbus/virtual_file_request_service_provider.h
+++ b/chrome/browser/ash/dbus/virtual_file_request_service_provider.h
@@ -48,9 +48,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::VirtualFileRequestServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_VIRTUAL_FILE_REQUEST_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/vm/plugin_vm_service_provider.h b/chrome/browser/ash/dbus/vm/plugin_vm_service_provider.h
index 135f7fa..daf83f9a 100644
--- a/chrome/browser/ash/dbus/vm/plugin_vm_service_provider.h
+++ b/chrome/browser/ash/dbus/vm/plugin_vm_service_provider.h
@@ -109,9 +109,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::PluginVmServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_VM_PLUGIN_VM_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/vm/vm_applications_service_provider.h b/chrome/browser/ash/dbus/vm/vm_applications_service_provider.h
index 42291a1..1f717d4 100644
--- a/chrome/browser/ash/dbus/vm/vm_applications_service_provider.h
+++ b/chrome/browser/ash/dbus/vm/vm_applications_service_provider.h
@@ -73,9 +73,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::VmApplicationsServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_VM_VM_APPLICATIONS_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/vm/vm_disk_management_service_provider.h b/chrome/browser/ash/dbus/vm/vm_disk_management_service_provider.h
index 5d3da4d..17234b3 100644
--- a/chrome/browser/ash/dbus/vm/vm_disk_management_service_provider.h
+++ b/chrome/browser/ash/dbus/vm/vm_disk_management_service_provider.h
@@ -70,9 +70,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::VmDiskManagementServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_VM_VM_DISK_MANAGEMENT_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/vm/vm_permission_service_provider.h b/chrome/browser/ash/dbus/vm/vm_permission_service_provider.h
index 5c9d468b..d77f8756 100644
--- a/chrome/browser/ash/dbus/vm/vm_permission_service_provider.h
+++ b/chrome/browser/ash/dbus/vm/vm_permission_service_provider.h
@@ -161,9 +161,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::VmPermissionServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_VM_VM_PERMISSION_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.cc b/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.cc
index 2d73fba..cd5c71e 100644
--- a/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.cc
+++ b/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.cc
@@ -70,7 +70,7 @@
     return;
   }
 
-  ash::guest_os::VmSKForwardingNativeMessageHost::
+  guest_os::VmSKForwardingNativeMessageHost::
       DeliverMessageToSKForwardingExtension(
           profile, request.message(),
           base::BindOnce(&VmSKForwardingServiceProvider::OnResponse,
diff --git a/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.h b/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.h
index 7d84833..5bd610aa 100644
--- a/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.h
+++ b/chrome/browser/ash/dbus/vm/vm_sk_forwarding_service_provider.h
@@ -56,9 +56,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-using ::ash::VmSKForwardingServiceProvider;
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DBUS_VM_VM_SK_FORWARDING_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/ash/device_name/device_name_store.h b/chrome/browser/ash/device_name/device_name_store.h
index 57beabff..3ce1c16f 100644
--- a/chrome/browser/ash/device_name/device_name_store.h
+++ b/chrome/browser/ash/device_name/device_name_store.h
@@ -125,9 +125,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the migration is finished.
-namespace chromeos {
-using ::ash::DeviceNameStore;
-}
-
 #endif  // CHROME_BROWSER_ASH_DEVICE_NAME_DEVICE_NAME_STORE_H_
diff --git a/chrome/browser/ash/device_name/fake_device_name_store.h b/chrome/browser/ash/device_name/fake_device_name_store.h
index b4f14dce..d906671 100644
--- a/chrome/browser/ash/device_name/fake_device_name_store.h
+++ b/chrome/browser/ash/device_name/fake_device_name_store.h
@@ -33,9 +33,4 @@
 
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the migration is finished.
-namespace chromeos {
-using ::ash::FakeDeviceNameStore;
-}
-
 #endif  // CHROME_BROWSER_ASH_DEVICE_NAME_FAKE_DEVICE_NAME_STORE_H_
diff --git a/chrome/browser/ash/device_sync/device_sync_client_factory.cc b/chrome/browser/ash/device_sync/device_sync_client_factory.cc
index 5e4f1329..235052e 100644
--- a/chrome/browser/ash/device_sync/device_sync_client_factory.cc
+++ b/chrome/browser/ash/device_sync/device_sync_client_factory.cc
@@ -48,7 +48,7 @@
  public:
   explicit DeviceSyncClientHolder(content::BrowserContext* context)
       : soft_bind_attestation_flow_(
-            std::make_unique<ash::attestation::SoftBindAttestationFlow>()),
+            std::make_unique<attestation::SoftBindAttestationFlow>()),
         device_sync_(CreateDeviceSyncImplForProfile(
             Profile::FromBrowserContext(context))),
         device_sync_client_(DeviceSyncClientImpl::Factory::Create()) {
@@ -79,7 +79,7 @@
     return DeviceSyncImpl::Factory::Create(
         IdentityManagerFactory::GetForProfile(profile),
         gcm::GCMProfileServiceFactory::GetForProfile(profile)->driver(),
-        profile->GetPrefs(), chromeos::GcmDeviceInfoProviderImpl::GetInstance(),
+        profile->GetPrefs(), GcmDeviceInfoProviderImpl::GetInstance(),
         ClientAppMetadataProviderServiceFactory::GetForProfile(profile),
         profile->GetURLLoaderFactory(), std::make_unique<base::OneShotTimer>(),
         base::BindRepeating(&DeviceSyncClientHolder::GetAttestationCertificates,
@@ -88,7 +88,7 @@
 
   void GetAttestationCertificates(
       Profile* profile,
-      ash::attestation::SoftBindAttestationFlow::Callback notify_callback,
+      attestation::SoftBindAttestationFlow::Callback notify_callback,
       const std::string& user_key) {
     const user_manager::User* user =
         ProfileHelper::Get()->GetUserByProfile(profile);
@@ -97,7 +97,7 @@
         user ? user->GetAccountId() : EmptyAccountId(), user_key);
   }
 
-  std::unique_ptr<ash::attestation::SoftBindAttestationFlow>
+  std::unique_ptr<attestation::SoftBindAttestationFlow>
       soft_bind_attestation_flow_;
 
   std::unique_ptr<DeviceSyncBase> device_sync_;
diff --git a/chrome/browser/ash/device_sync/device_sync_client_factory.h b/chrome/browser/ash/device_sync/device_sync_client_factory.h
index f6449773..870d12a 100644
--- a/chrome/browser/ash/device_sync/device_sync_client_factory.h
+++ b/chrome/browser/ash/device_sync/device_sync_client_factory.h
@@ -41,11 +41,4 @@
 }  // namespace device_sync
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the migration is finished.
-namespace chromeos {
-namespace device_sync {
-using ::ash::device_sync::DeviceSyncClientFactory;
-}
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_DEVICE_SYNC_DEVICE_SYNC_CLIENT_FACTORY_H_
diff --git a/chrome/browser/ash/diagnostics/diagnostics_browser_delegate_impl.cc b/chrome/browser/ash/diagnostics/diagnostics_browser_delegate_impl.cc
index 5647cbe3..400b3ab 100644
--- a/chrome/browser/ash/diagnostics/diagnostics_browser_delegate_impl.cc
+++ b/chrome/browser/ash/diagnostics/diagnostics_browser_delegate_impl.cc
@@ -21,7 +21,7 @@
 
   auto* user = user_manager::UserManager::Get()->GetActiveUser();
   DCHECK(user);
-  auto* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
+  auto* profile = ProfileHelper::Get()->GetProfileByUser(user);
 
   // Profile may be null if called before profile load is complete.
   if (profile == nullptr) {
diff --git a/chrome/browser/ash/diagnostics/diagnostics_browser_delegate_impl_unittest.cc b/chrome/browser/ash/diagnostics/diagnostics_browser_delegate_impl_unittest.cc
index caaf1697..5a63d34 100644
--- a/chrome/browser/ash/diagnostics/diagnostics_browser_delegate_impl_unittest.cc
+++ b/chrome/browser/ash/diagnostics/diagnostics_browser_delegate_impl_unittest.cc
@@ -42,7 +42,7 @@
   ~DiagnosticsBrowserDelegateImplTest() override = default;
 
   void SetUp() override {
-    user_manager_ = std::make_unique<ash::FakeChromeUserManager>();
+    user_manager_ = std::make_unique<FakeChromeUserManager>();
     user_manager_->Initialize();
     ProfileHelper::Get()->Initialize();
     LoginState::Initialize();
@@ -104,11 +104,11 @@
   }
 
  protected:
-  ash::diagnostics::DiagnosticsBrowserDelegateImpl delegate_;
+  diagnostics::DiagnosticsBrowserDelegateImpl delegate_;
 
  private:
   content::BrowserTaskEnvironment task_env_{};
-  std::unique_ptr<ash::FakeChromeUserManager> user_manager_;
+  std::unique_ptr<FakeChromeUserManager> user_manager_;
   TestingProfileManager profile_manager_{TestingBrowserProcess::GetGlobal()};
   TestingPrefServiceSimple local_state_;
 };
diff --git a/chrome/browser/ash/eche_app/eche_app_manager_factory.h b/chrome/browser/ash/eche_app/eche_app_manager_factory.h
index a3943b0..6c8ce6d0 100644
--- a/chrome/browser/ash/eche_app/eche_app_manager_factory.h
+++ b/chrome/browser/ash/eche_app/eche_app_manager_factory.h
@@ -135,12 +135,4 @@
 }  // namespace eche_app
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the //chrome/browser/chromeos
-// source migration is finished.
-namespace chromeos {
-namespace eche_app {
-using ::ash::eche_app::EcheAppManagerFactory;
-}
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_ECHE_APP_ECHE_APP_MANAGER_FACTORY_H_
diff --git a/chrome/browser/ash/eche_app/eche_app_manager_factory_unittest.cc b/chrome/browser/ash/eche_app/eche_app_manager_factory_unittest.cc
index 28fff79..0b76579 100644
--- a/chrome/browser/ash/eche_app/eche_app_manager_factory_unittest.cc
+++ b/chrome/browser/ash/eche_app/eche_app_manager_factory_unittest.cc
@@ -46,10 +46,9 @@
     DCHECK(profile_);
     DCHECK(test_web_view_factory_.get());
     ChromeAshTestBase::SetUp();
-    eche_tray_ =
-        ash::StatusAreaWidgetTestHelper::GetStatusAreaWidget()->eche_tray();
-    phone_hub_tray_ = ash::StatusAreaWidgetTestHelper::GetStatusAreaWidget()
-                          ->phone_hub_tray();
+    eche_tray_ = StatusAreaWidgetTestHelper::GetStatusAreaWidget()->eche_tray();
+    phone_hub_tray_ =
+        StatusAreaWidgetTestHelper::GetStatusAreaWidget()->phone_hub_tray();
     display_service_ =
         std::make_unique<NotificationDisplayServiceTester>(GetProfile());
     eche_app_manager_factory_ = EcheAppManagerFactory::GetInstance();
@@ -138,8 +137,7 @@
     DCHECK(profile_);
     DCHECK(test_web_view_factory_.get());
     ChromeAshTestBase::SetUp();
-    eche_tray_ =
-        ash::StatusAreaWidgetTestHelper::GetStatusAreaWidget()->eche_tray();
+    eche_tray_ = StatusAreaWidgetTestHelper::GetStatusAreaWidget()->eche_tray();
   }
 
   TestingProfile* GetProfile() { return profile_; }
diff --git a/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl.h b/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl.h
index be52c48..87a69a82 100644
--- a/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl.h
+++ b/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl.h
@@ -47,7 +47,7 @@
       mojo::PendingReceiver<mojom::EnhancedNetworkTts> receiver,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
-  // ash::enhanced_network_tts::mojom::EnhancedNetworkTts:
+  // mojom::EnhancedNetworkTts:
   void GetAudioData(mojom::TtsRequestPtr request,
                     GetAudioDataCallback callback) override;
 
diff --git a/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl_unittest.cc b/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl_unittest.cc
index f9e0cf4..a4f10e9 100644
--- a/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl_unittest.cc
+++ b/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_impl_unittest.cc
@@ -143,7 +143,7 @@
     receiver_.Bind(std::move(receiver));
   }
 
-  // ash::enhanced_network_tts::mojom::AudioDataObserver:
+  // mojom::AudioDataObserver:
   void OnAudioDataReceived(mojom::TtsResponsePtr response) override {
     received_responses_.push_back(std::move(response));
   }
diff --git a/chrome/browser/ash/exo/chrome_data_exchange_delegate.cc b/chrome/browser/ash/exo/chrome_data_exchange_delegate.cc
index ee2de0c..654e4c2 100644
--- a/chrome/browser/ash/exo/chrome_data_exchange_delegate.cc
+++ b/chrome/browser/ash/exo/chrome_data_exchange_delegate.cc
@@ -338,7 +338,7 @@
     aura::Window* target) const {
   auto* top_level_window = target->GetToplevelWindow();
 
-  if (ash::IsArcWindow(top_level_window))
+  if (IsArcWindow(top_level_window))
     return ui::EndpointType::kArc;
 
   if (borealis::BorealisWindowManager::IsBorealisWindow(top_level_window))
diff --git a/chrome/browser/ash/exo/chrome_data_exchange_delegate_unittest.cc b/chrome/browser/ash/exo/chrome_data_exchange_delegate_unittest.cc
index 55f0020c..0da2f0e 100644
--- a/chrome/browser/ash/exo/chrome_data_exchange_delegate_unittest.cc
+++ b/chrome/browser/ash/exo/chrome_data_exchange_delegate_unittest.cc
@@ -73,7 +73,7 @@
  public:
   void SetUp() override {
     ChunneldClient::InitializeFake();
-    ash::CiceroneClient::InitializeFake();
+    CiceroneClient::InitializeFake();
     ConciergeClient::InitializeFake();
     SeneschalClient::InitializeFake();
 
@@ -119,7 +119,7 @@
     profile_.reset();
     SeneschalClient::Shutdown();
     ConciergeClient::Shutdown();
-    ash::CiceroneClient::Shutdown();
+    CiceroneClient::Shutdown();
     ChunneldClient::Shutdown();
   }
 
@@ -152,17 +152,17 @@
   aura::Window* arc_toplevel = aura::test::CreateTestWindowWithDelegate(
       &delegate_, 0, gfx::Rect(), &container_window);
   arc_toplevel->SetProperty(aura::client::kAppType,
-                            static_cast<int>(ash::AppType::ARC_APP));
-  ASSERT_TRUE(ash::IsArcWindow(arc_toplevel));
+                            static_cast<int>(AppType::ARC_APP));
+  ASSERT_TRUE(IsArcWindow(arc_toplevel));
   aura::Window* arc_window =
       aura::test::CreateTestWindowWithBounds(gfx::Rect(), arc_toplevel);
-  ASSERT_TRUE(ash::IsArcWindow(arc_window->GetToplevelWindow()));
+  ASSERT_TRUE(IsArcWindow(arc_window->GetToplevelWindow()));
 
   // Crostini:
   aura::Window* crostini_toplevel = aura::test::CreateTestWindowWithDelegate(
       &delegate_, 0, gfx::Rect(), &container_window);
   crostini_toplevel->SetProperty(aura::client::kAppType,
-                                 static_cast<int>(ash::AppType::CROSTINI_APP));
+                                 static_cast<int>(AppType::CROSTINI_APP));
   ASSERT_TRUE(crostini::IsCrostiniWindow(crostini_toplevel));
   aura::Window* crostini_window =
       aura::test::CreateTestWindowWithBounds(gfx::Rect(), crostini_toplevel);
diff --git a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc
index feaf95a..5068a76 100644
--- a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc
@@ -100,6 +100,7 @@
 #include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h"
 #include "chrome/browser/ash/login/lock/screen_locker.h"
 #include "chrome/browser/ash/login/ui/login_display_host.h"
+#include "chrome/browser/ash/login/wizard_context.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_installer.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_installer_factory.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_pref_names.h"
@@ -1571,7 +1572,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DVLOG(1) << "AutotestPrivateSetTouchpadSensitivityFunction " << params->value;
 
-  chromeos::system::InputDeviceSettings::Get()->SetTouchpadSensitivity(
+  ash::system::InputDeviceSettings::Get()->SetTouchpadSensitivity(
       params->value);
   return RespondNow(NoArguments());
 }
@@ -1589,7 +1590,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DVLOG(1) << "AutotestPrivateSetTapToClickFunction " << params->enabled;
 
-  chromeos::system::InputDeviceSettings::Get()->SetTapToClick(params->enabled);
+  ash::system::InputDeviceSettings::Get()->SetTapToClick(params->enabled);
   return RespondNow(NoArguments());
 }
 
@@ -1607,8 +1608,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DVLOG(1) << "AutotestPrivateSetThreeFingerClickFunction " << params->enabled;
 
-  chromeos::system::InputDeviceSettings::Get()->SetThreeFingerClick(
-      params->enabled);
+  ash::system::InputDeviceSettings::Get()->SetThreeFingerClick(params->enabled);
   return RespondNow(NoArguments());
 }
 
@@ -1625,7 +1625,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DVLOG(1) << "AutotestPrivateSetTapDraggingFunction " << params->enabled;
 
-  chromeos::system::InputDeviceSettings::Get()->SetTapDragging(params->enabled);
+  ash::system::InputDeviceSettings::Get()->SetTapDragging(params->enabled);
   return RespondNow(NoArguments());
 }
 
@@ -1643,8 +1643,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DVLOG(1) << "AutotestPrivateSetNaturalScrollFunction " << params->enabled;
 
-  chromeos::system::InputDeviceSettings::Get()->SetNaturalScroll(
-      params->enabled);
+  ash::system::InputDeviceSettings::Get()->SetNaturalScroll(params->enabled);
   return RespondNow(NoArguments());
 }
 
@@ -1662,8 +1661,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DVLOG(1) << "AutotestPrivateSetMouseSensitivityFunction " << params->value;
 
-  chromeos::system::InputDeviceSettings::Get()->SetMouseSensitivity(
-      params->value);
+  ash::system::InputDeviceSettings::Get()->SetMouseSensitivity(params->value);
   return RespondNow(NoArguments());
 }
 
@@ -1681,8 +1679,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DVLOG(1) << "AutotestPrivateSetPrimaryButtonRightFunction " << params->right;
 
-  chromeos::system::InputDeviceSettings::Get()->SetPrimaryButtonRight(
-      params->right);
+  ash::system::InputDeviceSettings::Get()->SetPrimaryButtonRight(params->right);
   return RespondNow(NoArguments());
 }
 
@@ -1701,7 +1698,7 @@
   DVLOG(1) << "AutotestPrivateSetMouseReverseScrollFunction "
            << params->enabled;
 
-  chromeos::system::InputDeviceSettings::Get()->SetMouseReverseScroll(
+  ash::system::InputDeviceSettings::Get()->SetMouseReverseScroll(
       params->enabled);
   return RespondNow(NoArguments());
 }
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
index 7b33cdf..83fdcf7 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -3061,7 +3061,7 @@
     const std::string* timezone = value.FindString("timezone");
     ASSERT_TRUE(timezone);
     auto* user = user_manager::UserManager::Get()->GetActiveUser();
-    chromeos::system::SetSystemTimezone(user, *timezone);
+    ash::system::SetSystemTimezone(user, *timezone);
     return;
   }
 
diff --git a/chrome/browser/ash/file_system_provider/abort_callback.h b/chrome/browser/ash/file_system_provider/abort_callback.h
index ac980fa..7eb3d0b 100644
--- a/chrome/browser/ash/file_system_provider/abort_callback.h
+++ b/chrome/browser/ash/file_system_provider/abort_callback.h
@@ -16,11 +16,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::AbortCallback;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_ABORT_CALLBACK_H_
diff --git a/chrome/browser/ash/file_system_provider/icon_set.h b/chrome/browser/ash/file_system_provider/icon_set.h
index 069f9d65..9585f42 100644
--- a/chrome/browser/ash/file_system_provider/icon_set.h
+++ b/chrome/browser/ash/file_system_provider/icon_set.h
@@ -44,11 +44,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::IconSet;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_ICON_SET_H_
diff --git a/chrome/browser/ash/file_system_provider/mount_path_util.h b/chrome/browser/ash/file_system_provider/mount_path_util.h
index 27b2861d..267ac52 100644
--- a/chrome/browser/ash/file_system_provider/mount_path_util.h
+++ b/chrome/browser/ash/file_system_provider/mount_path_util.h
@@ -83,13 +83,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-namespace util {
-using ::ash::file_system_provider::util::GetMountPath;
-}  // namespace util
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_MOUNT_PATH_UTIL_H_
diff --git a/chrome/browser/ash/file_system_provider/operations/operation.cc b/chrome/browser/ash/file_system_provider/operations/operation.cc
index 4031fdc..b48f2a3 100644
--- a/chrome/browser/ash/file_system_provider/operations/operation.cc
+++ b/chrome/browser/ash/file_system_provider/operations/operation.cc
@@ -22,16 +22,16 @@
 namespace ash {
 namespace file_system_provider {
 namespace operations {
+
 namespace {
 
 // This method is only used when Lacros is enabled. It's a callback from Lacros
 // indicating whether the operation was successfully forwarded. If the operation
 // could not be forwarded then the file system request manager must be informed.
-void OperationForwarded(ash::file_system_provider::ProviderId provider_id,
+void OperationForwarded(ProviderId provider_id,
                         const std::string& file_system_id,
                         int request_id,
                         bool delivery_failure) {
-  using ash::file_system_provider::Service;
   // Successful deliveries will go through the FileSystemProvider mojom path.
   if (!delivery_failure)
     return;
diff --git a/chrome/browser/ash/file_system_provider/provided_file_system_info.h b/chrome/browser/ash/file_system_provider/provided_file_system_info.h
index bb2e9138..6640f35d 100644
--- a/chrome/browser/ash/file_system_provider/provided_file_system_info.h
+++ b/chrome/browser/ash/file_system_provider/provided_file_system_info.h
@@ -142,13 +142,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::MountOptions;
-using ::ash::file_system_provider::ProvidedFileSystemInfo;
-using ::ash::file_system_provider::ProviderId;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_PROVIDED_FILE_SYSTEM_INFO_H_
diff --git a/chrome/browser/ash/file_system_provider/provided_file_system_interface.h b/chrome/browser/ash/file_system_provider/provided_file_system_interface.h
index a25f28f..78f3a9d 100644
--- a/chrome/browser/ash/file_system_provider/provided_file_system_interface.h
+++ b/chrome/browser/ash/file_system_provider/provided_file_system_interface.h
@@ -284,16 +284,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::Action;
-using ::ash::file_system_provider::EntryMetadata;
-using ::ash::file_system_provider::OPEN_FILE_MODE_READ;
-using ::ash::file_system_provider::OPEN_FILE_MODE_WRITE;
-using ::ash::file_system_provider::OpenedFiles;
-using ::ash::file_system_provider::OpenFileMode;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_PROVIDED_FILE_SYSTEM_INTERFACE_H_
diff --git a/chrome/browser/ash/file_system_provider/provided_file_system_observer.h b/chrome/browser/ash/file_system_provider/provided_file_system_observer.h
index 78e6c5c..e0196fe 100644
--- a/chrome/browser/ash/file_system_provider/provided_file_system_observer.h
+++ b/chrome/browser/ash/file_system_provider/provided_file_system_observer.h
@@ -59,11 +59,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::ProvidedFileSystemObserver;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_PROVIDED_FILE_SYSTEM_OBSERVER_H_
diff --git a/chrome/browser/ash/file_system_provider/provider_interface.h b/chrome/browser/ash/file_system_provider/provider_interface.h
index 6706f10..966d20a 100644
--- a/chrome/browser/ash/file_system_provider/provider_interface.h
+++ b/chrome/browser/ash/file_system_provider/provider_interface.h
@@ -76,13 +76,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::Capabilities;
-using ::ash::file_system_provider::ProvidedFileSystemInterface;
-using ::ash::file_system_provider::ProviderInterface;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_PROVIDER_INTERFACE_H_
diff --git a/chrome/browser/ash/file_system_provider/service.h b/chrome/browser/ash/file_system_provider/service.h
index d9f94a2..f95d3dd 100644
--- a/chrome/browser/ash/file_system_provider/service.h
+++ b/chrome/browser/ash/file_system_provider/service.h
@@ -218,11 +218,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::Service;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_SERVICE_H_
diff --git a/chrome/browser/ash/file_system_provider/service_factory.h b/chrome/browser/ash/file_system_provider/service_factory.h
index 68ec9b6..6238cd99 100644
--- a/chrome/browser/ash/file_system_provider/service_factory.h
+++ b/chrome/browser/ash/file_system_provider/service_factory.h
@@ -45,11 +45,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::ServiceFactory;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ash/file_system_provider/watcher.h b/chrome/browser/ash/file_system_provider/watcher.h
index 10621b9..13bb794 100644
--- a/chrome/browser/ash/file_system_provider/watcher.h
+++ b/chrome/browser/ash/file_system_provider/watcher.h
@@ -83,11 +83,4 @@
 }  // namespace file_system_provider
 }  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
-namespace chromeos {
-namespace file_system_provider {
-using ::ash::file_system_provider::Watchers;
-}  // namespace file_system_provider
-}  // namespace chromeos
-
 #endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_WATCHER_H_
diff --git a/chrome/browser/ash/first_party_sets/first_party_sets_policy_initialization_browsertest.cc b/chrome/browser/ash/first_party_sets/first_party_sets_policy_initialization_browsertest.cc
index a4987c23..d72c8bd7 100644
--- a/chrome/browser/ash/first_party_sets/first_party_sets_policy_initialization_browsertest.cc
+++ b/chrome/browser/ash/first_party_sets/first_party_sets_policy_initialization_browsertest.cc
@@ -51,7 +51,7 @@
     LoginManagerTest::SetUpCommandLine(command_line);
     // Allow policy fetches to fail so that these tests retrieve policy from a
     // MockConfigurationPolicyProvider.
-    command_line->AppendSwitch(ash::switches::kAllowFailedPolicyFetchForTest);
+    command_line->AppendSwitch(switches::kAllowFailedPolicyFetchForTest);
   }
 
   // If `overrides` is provided, this sets the FirstPartySetsEnabled and
@@ -76,7 +76,7 @@
   AccountId test_account_id() { return test_account_id_; }
 
  private:
-  ash::LoginManagerMixin login_mixin_{&mixin_host_};
+  LoginManagerMixin login_mixin_{&mixin_host_};
   testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_;
   policy::PolicyMap policy_;
   AccountId test_account_id_;
diff --git a/chrome/browser/ash/first_run/first_run.cc b/chrome/browser/ash/first_run/first_run.cc
index 6398914..bd527bd4 100644
--- a/chrome/browser/ash/first_run/first_run.cc
+++ b/chrome/browser/ash/first_run/first_run.cc
@@ -91,7 +91,7 @@
  private:
   explicit AppLauncher(Profile* profile) : profile_(profile) {
     profile->AddObserver(this);
-    ash::SystemWebAppManager::Get(profile)->on_apps_synchronized().Post(
+    SystemWebAppManager::Get(profile)->on_apps_synchronized().Post(
         FROM_HERE, base::BindOnce(&AppLauncher::LaunchHelpApp, AsWeakPtr()));
   }
 
@@ -100,7 +100,7 @@
   AppLauncher& operator=(const AppLauncher&) = delete;
 
   void LaunchHelpApp() {
-    ash::LaunchSystemWebAppAsync(profile_, ash::SystemWebAppType::HELP);
+    LaunchSystemWebAppAsync(profile_, SystemWebAppType::HELP);
     profile_->GetPrefs()->SetBoolean(prefs::kFirstRunTutorialShown, true);
     delete this;
   }
@@ -129,7 +129,7 @@
   profile->GetPrefs()->SetBoolean(prefs::kHelpAppShouldShowGetStarted,
                                   ShouldShowGetStarted(profile, user_manager));
   profile->GetPrefs()->SetBoolean(prefs::kHelpAppTabletModeDuringOobe,
-                                  ash::TabletMode::IsInTabletMode());
+                                  TabletMode::IsInTabletMode());
 
   if (WizardController::default_controller())
     WizardController::default_controller()->PrepareFirstRunPrefs();
@@ -147,8 +147,8 @@
     return true;
   }
 
-  // ash::TabletMode does not exist in some tests.
-  if (ash::TabletMode::Get() && ash::TabletMode::Get()->InTabletMode())
+  // TabletMode does not exist in some tests.
+  if (TabletMode::Get() && TabletMode::Get()->InTabletMode())
     return false;
 
   if (command_line->HasSwitch(::switches::kTestType))
diff --git a/chrome/browser/ash/floating_workspace/floating_workspace_service_unittest.cc b/chrome/browser/ash/floating_workspace/floating_workspace_service_unittest.cc
index 0b539c46..9c907fa 100644
--- a/chrome/browser/ash/floating_workspace/floating_workspace_service_unittest.cc
+++ b/chrome/browser/ash/floating_workspace/floating_workspace_service_unittest.cc
@@ -12,7 +12,10 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace ash {
+
 namespace {
+
 constexpr char local_session_name[] = "local_session";
 constexpr char remote_session_1_name[] = "remote_session_1";
 constexpr char remote_session_2_name[] = "remote_session_2";
@@ -80,12 +83,11 @@
 
 }  // namespace
 
-namespace ash {
-class TestFloatingWorkSpaceService : public ash::FloatingWorkspaceService {
+class TestFloatingWorkSpaceService : public FloatingWorkspaceService {
  public:
   explicit TestFloatingWorkSpaceService(TestingProfile* profile,
                                         TestFloatingWorkspaceVersion version)
-      : ash::FloatingWorkspaceService(profile) {
+      : FloatingWorkspaceService(profile) {
     InitForTest(version);
     mock_open_tabs_ = std::make_unique<MockOpenTabsUIDelegate>();
   }
diff --git a/chrome/browser/ash/floating_workspace/floating_workspace_util.cc b/chrome/browser/ash/floating_workspace/floating_workspace_util.cc
index 7767c32..beec53a 100644
--- a/chrome/browser/ash/floating_workspace/floating_workspace_util.cc
+++ b/chrome/browser/ash/floating_workspace/floating_workspace_util.cc
@@ -16,10 +16,10 @@
 namespace ash {
 
 namespace {
+
 PrefService* GetPrimaryUserPrefService() {
   auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
-  auto* user_profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+  auto* user_profile = ProfileHelper::Get()->GetProfileByUser(primary_user);
   return user_profile->GetPrefs();
 }
 
@@ -36,13 +36,13 @@
   DCHECK(pref_service);
 
   const PrefService::Preference* floating_workspace_pref =
-      pref_service->FindPreference(ash::prefs::kFloatingWorkspaceEnabled);
+      pref_service->FindPreference(prefs::kFloatingWorkspaceEnabled);
 
   DCHECK(floating_workspace_pref);
 
   if (floating_workspace_pref->IsManaged()) {
     // If there is a policy managing the pref, return what is set by policy.
-    return pref_service->GetBoolean(ash::prefs::kFloatingWorkspaceEnabled);
+    return pref_service->GetBoolean(prefs::kFloatingWorkspaceEnabled);
   }
   // If the policy is not set, return feature flag status.
   return features::IsFloatingWorkspaceEnabled();
diff --git a/chrome/browser/ash/login/screens/sync_consent_browsertest.cc b/chrome/browser/ash/login/screens/sync_consent_browsertest.cc
index e992ea9f..4ab6aea 100644
--- a/chrome/browser/ash/login/screens/sync_consent_browsertest.cc
+++ b/chrome/browser/ash/login/screens/sync_consent_browsertest.cc
@@ -503,7 +503,9 @@
 };
 
 // TODO(crbug.com/1311979): Test failed on ChromeOS.
-#if !defined(NDEBUG)
+// TODO(crbug.com/1392782): Test failed on chromium/ci/Linux ChromiumOS.
+#undef MAYBE_Accept
+#if !defined(NDEBUG) || BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_Accept DISABLED_Accept
 #else
 #define MAYBE_Accept Accept
@@ -675,6 +677,7 @@
 };
 
 // TODO(crbug.com/1312384): Test failed on linux-chromeos-dbg.
+#undef MAYBE_Accept
 #if !defined(NDEBUG)
 #define MAYBE_Accept DISABLED_Accept
 #else
diff --git a/chrome/browser/ash/login/session/user_session_manager.cc b/chrome/browser/ash/login/session/user_session_manager.cc
index 2ed0185..bce5ff4 100644
--- a/chrome/browser/ash/login/session/user_session_manager.cc
+++ b/chrome/browser/ash/login/session/user_session_manager.cc
@@ -931,8 +931,8 @@
           : Profile::APP_LOCALE_CHANGED_VIA_LOGIN;
 
   // check if pref_locale is allowed by policy (AllowedLanguages)
-  if (!chromeos::locale_util::IsAllowedUILanguage(pref_locale, prefs)) {
-    pref_locale = chromeos::locale_util::GetAllowedFallbackUILanguage(prefs);
+  if (!locale_util::IsAllowedUILanguage(pref_locale, prefs)) {
+    pref_locale = locale_util::GetAllowedFallbackUILanguage(prefs);
     app_locale_changed_via = Profile::APP_LOCALE_CHANGED_VIA_POLICY;
   }
 
diff --git a/chrome/browser/cart/cart_handler.cc b/chrome/browser/cart/cart_handler.cc
index 73aefd3..98f2d32 100644
--- a/chrome/browser/cart/cart_handler.cc
+++ b/chrome/browser/cart/cart_handler.cc
@@ -69,6 +69,11 @@
 void CartHandler::GetCartDataCallback(GetMerchantCartsCallback callback,
                                       bool success,
                                       std::vector<CartDB::KeyAndValue> res) {
+  DCHECK(success);
+  if (!success) {
+    std::move(callback).Run({});
+    return;
+  }
   std::vector<chrome_cart::mojom::MerchantCartPtr> carts;
   bool show_discount = cart_service_->IsCartDiscountEnabled();
   for (CartDB::KeyAndValue proto_pair : res) {
diff --git a/chrome/browser/cart/cart_service.cc b/chrome/browser/cart/cart_service.cc
index e8443c6..cc86f25 100644
--- a/chrome/browser/cart/cart_service.cc
+++ b/chrome/browser/cart/cart_service.cc
@@ -823,6 +823,11 @@
 void CartService::OnLoadCarts(CartDB::LoadCallback callback,
                               bool success,
                               std::vector<CartDB::KeyAndValue> proto_pairs) {
+  DCHECK(success);
+  if (!success) {
+    std::move(callback).Run(success, {});
+    return;
+  }
   if (commerce::IsFakeDataEnabled()) {
     std::sort(proto_pairs.begin(), proto_pairs.end(),
               CompareTimeStampForProtoPair);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 9f257c5d..2fef17a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3253,11 +3253,13 @@
 
   switch (operation) {
     case AttributionReportingOperation::kSource:
+    case AttributionReportingOperation::kSourceVerboseDebugReport:
       DCHECK(source_origin);
       DCHECK(reporting_origin);
       return privacy_sandbox_settings->IsAttributionReportingAllowed(
           *source_origin, *reporting_origin);
     case AttributionReportingOperation::kTrigger:
+    case AttributionReportingOperation::kTriggerVerboseDebugReport:
       DCHECK(destination_origin);
       DCHECK(reporting_origin);
       return privacy_sandbox_settings->IsAttributionReportingAllowed(
diff --git a/chrome/browser/content_settings/chrome_content_settings_utils.cc b/chrome/browser/content_settings/chrome_content_settings_utils.cc
index 90a7877..54ba070 100644
--- a/chrome/browser/content_settings/chrome_content_settings_utils.cc
+++ b/chrome/browser/content_settings/chrome_content_settings_utils.cc
@@ -43,8 +43,6 @@
   if (location_bar)
     location_bar->UpdateContentSettingsIcons();
 
-// TODO(https://crbug.com/1346734): Enable this on all platforms.
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   // The document PiP window does not have a location bar, but has some content
   // setting views that need to be updated too.
   if (browser->is_type_picture_in_picture()) {
@@ -54,8 +52,6 @@
     frame_view->UpdateContentSettingsIcons();
   }
 #endif
-
-#endif
 }
 
 }  // namespace content_settings
diff --git a/chrome/browser/extensions/api/favicon/favicon_util.cc b/chrome/browser/extensions/api/favicon/favicon_util.cc
index e720f73872..1e1bffd 100644
--- a/chrome/browser/extensions/api/favicon/favicon_util.cc
+++ b/chrome/browser/extensions/api/favicon/favicon_util.cc
@@ -81,8 +81,8 @@
     return;
   }
 
-  // Don't make requests to the favicon server if a favicon can't be found.
-  constexpr bool kAllowFaviconServerFallback = false;
+  // Use exact URL match instead of host match
+  constexpr bool kAllowFallbackToHost = false;
 
   int size_in_pixels = parsed.size_in_dip;
 
@@ -92,7 +92,7 @@
                                            ServiceAccessType::EXPLICIT_ACCESS);
   favicon_service->GetRawFaviconForPageURL(
       GURL(parsed.page_url), {favicon_base::IconType::kFavicon}, size_in_pixels,
-      kAllowFaviconServerFallback,
+      kAllowFallbackToHost,
       base::BindOnce(&favicon_util::OnFaviconAvailable, std::move(callback),
                      size_in_pixels),
       tracker);
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
index 2d76451..a30a5a4 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
@@ -159,18 +159,30 @@
   GaiaRemoteConsentFlowFailed(gaia_failure);
 }
 
+content::StoragePartition* GaiaRemoteConsentFlow::GetStoragePartition() {
+  content::StoragePartition* storage_partition = web_flow_->GetGuestPartition();
+  if (!storage_partition) {
+    // `web_flow_` doesn't have a guest partition only when the Auth Through
+    // Browser Tab flow is used.
+    DCHECK(base::FeatureList::IsEnabled(kWebAuthFlowInBrowserTab));
+    storage_partition = profile_->GetDefaultStoragePartition();
+  }
+
+  return storage_partition;
+}
+
 std::unique_ptr<GaiaAuthFetcher>
 GaiaRemoteConsentFlow::CreateGaiaAuthFetcherForPartition(
     GaiaAuthConsumer* consumer,
     const gaia::GaiaSource& source) {
   return std::make_unique<GaiaAuthFetcher>(
       consumer, source,
-      web_flow_->GetGuestPartition()->GetURLLoaderFactoryForBrowserProcess());
+      GetStoragePartition()->GetURLLoaderFactoryForBrowserProcess());
 }
 
 network::mojom::CookieManager*
 GaiaRemoteConsentFlow::GetCookieManagerForPartition() {
-  return web_flow_->GetGuestPartition()->GetCookieManagerForBrowserProcess();
+  return GetStoragePartition()->GetCookieManagerForBrowserProcess();
 }
 
 void GaiaRemoteConsentFlow::OnEndBatchOfRefreshTokenStateChanges() {
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
index 0ee436e..322db8d 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
@@ -13,6 +13,7 @@
 #include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
+#include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_mint_token_flow.h"
@@ -89,6 +90,8 @@
 
   void DetachWebAuthFlow();
 
+  content::StoragePartition* GetStoragePartition();
+
   raw_ptr<Delegate> delegate_;
   raw_ptr<Profile> profile_;
   CoreAccountId account_id_;
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.cc b/chrome/browser/extensions/api/identity/web_auth_flow.cc
index 92233f4..c3c414e 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/web_auth_flow.cc
@@ -18,15 +18,20 @@
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
 #include "chrome/common/extensions/api/identity_private.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "components/guest_view/browser/guest_view_base.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "crypto/random.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/event_router.h"
@@ -88,6 +93,10 @@
              "PersistentStorageForWebAuthFlow",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kWebAuthFlowInBrowserTab,
+             "WebAuthFlowInBrowserTab",
+             base::FeatureState::FEATURE_DISABLED_BY_DEFAULT);
+
 WebAuthFlow::WebAuthFlow(Delegate* delegate,
                          Profile* profile,
                          const GURL& provider_url,
@@ -97,14 +106,17 @@
       profile_(profile),
       provider_url_(provider_url),
       mode_(mode),
-      partition_(partition),
-      embedded_window_created_(false) {
+      partition_(partition) {
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("identity", "WebAuthFlow", this);
 }
 
 WebAuthFlow::~WebAuthFlow() {
   DCHECK(!delegate_);
 
+  if (using_auth_with_browser_tab_ && web_contents()) {
+    web_contents()->Close();
+  }
+
   // Stop listening to notifications first since some of the code
   // below may generate notifications.
   WebContentsObserver::Observe(nullptr);
@@ -122,6 +134,19 @@
   DCHECK(profile_);
   DCHECK(!profile_->IsOffTheRecord());
 
+  if (partition_ == WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW &&
+      base::FeatureList::IsEnabled(kWebAuthFlowInBrowserTab)) {
+    using_auth_with_browser_tab_ = true;
+
+    content::WebContents::CreateParams params(profile_);
+    web_contents_ = content::WebContents::Create(params);
+    WebContentsObserver::Observe(web_contents_.get());
+
+    content::NavigationController::LoadURLParams load_params(provider_url_);
+    web_contents_->GetController().LoadURLWithParams(load_params);
+    return;
+  }
+
   AppWindowRegistry::Get(profile_)->AddObserver(this);
 
   // Attach a random ID string to the window so we can recognize it
@@ -165,6 +190,11 @@
 }
 
 content::StoragePartition* WebAuthFlow::GetGuestPartition() {
+  // When using the Auth through the Browser Tab, the guest partition shouldn't
+  // be used, consider using `Profile::GetDefaultStoragePartition()` instead.
+  if (base::FeatureList::IsEnabled(kWebAuthFlowInBrowserTab))
+    return nullptr;
+
   return profile_->GetStoragePartition(
       GetWebViewPartitionConfig(partition_, profile_));
 }
@@ -211,14 +241,31 @@
   }
 }
 
+bool WebAuthFlow::IsObservingProviderWebContents() const {
+  return web_contents() &&
+         (embedded_window_created_ || using_auth_with_browser_tab_);
+}
+
 void WebAuthFlow::BeforeUrlLoaded(const GURL& url) {
-  if (delegate_ && embedded_window_created_)
+  if (delegate_ && IsObservingProviderWebContents())
     delegate_->OnAuthFlowURLChange(url);
 }
 
 void WebAuthFlow::AfterUrlLoaded() {
-  if (delegate_ && embedded_window_created_ && mode_ == WebAuthFlow::SILENT)
+  if (delegate_ && IsObservingProviderWebContents() &&
+      mode_ == WebAuthFlow::SILENT) {
     delegate_->OnAuthFlowFailure(WebAuthFlow::INTERACTION_REQUIRED);
+  }
+
+  // If `web_contents_` is nullptr, this means that the interactive tab has
+  // already been opened once.
+  if (delegate_ && using_auth_with_browser_tab_ &&
+      mode_ == WebAuthFlow::INTERACTIVE && web_contents_) {
+    chrome::ScopedTabbedBrowserDisplayer browser_displayer(profile_);
+    NavigateParams params(browser_displayer.browser(),
+                          std::move(web_contents_));
+    Navigate(&params);
+  }
 }
 
 void WebAuthFlow::InnerWebContentsCreated(
@@ -235,10 +282,19 @@
 
 void WebAuthFlow::PrimaryMainFrameRenderProcessGone(
     base::TerminationStatus status) {
-  if (delegate_)
+  // When in `using_auth_with_browser_tab_` mode,
+  // `WebAuthFlow::WebContentsDestroyed()` takes care of this flow.
+  if (delegate_ && !using_auth_with_browser_tab_)
     delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
 }
 
+void WebAuthFlow::WebContentsDestroyed() {
+  WebContentsObserver::Observe(nullptr);
+  if (delegate_) {
+    delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
+  }
+}
+
 void WebAuthFlow::TitleWasSet(content::NavigationEntry* entry) {
   if (delegate_)
     delegate_->OnAuthFlowTitleChange(base::UTF16ToUTF8(entry->GetTitle()));
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.h b/chrome/browser/extensions/api/identity/web_auth_flow.h
index 9be65ad1..828b54c 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow.h
+++ b/chrome/browser/extensions/api/identity/web_auth_flow.h
@@ -28,6 +28,10 @@
 // across browser restarts.
 BASE_DECLARE_FEATURE(kPersistentStorageForWebAuthFlow);
 
+// When enabled, use authentication through a browser tab, instead of
+// an app window.
+BASE_DECLARE_FEATURE(kWebAuthFlowInBrowserTab);
+
 // Controller class for web based auth flows. The WebAuthFlow creates
 // a dialog window in the scope approval component app by firing an
 // event. A webview embedded in the dialog will navigate to the
@@ -124,6 +128,7 @@
       content::WebContents* inner_web_contents) override;
   void PrimaryMainFrameRenderProcessGone(
       base::TerminationStatus status) override;
+  void WebContentsDestroyed() override;
   void TitleWasSet(content::NavigationEntry* entry) override;
   void DidStartNavigation(
       content::NavigationHandle* navigation_handle) override;
@@ -135,15 +140,28 @@
   void BeforeUrlLoaded(const GURL& url);
   void AfterUrlLoaded();
 
-  raw_ptr<Delegate> delegate_;
-  raw_ptr<Profile> profile_;
-  GURL provider_url_;
-  Mode mode_;
-  Partition partition_;
+  bool IsObservingProviderWebContents() const;
 
-  raw_ptr<AppWindow> app_window_;
+  raw_ptr<Delegate> delegate_ = nullptr;
+  const raw_ptr<Profile> profile_;
+  const GURL provider_url_;
+  const Mode mode_;
+  const Partition partition_;
+
+  // Variables used only if displaying the auth flow in an app window.
+  raw_ptr<AppWindow> app_window_ = nullptr;
   std::string app_window_key_;
-  bool embedded_window_created_;
+  bool embedded_window_created_ = false;
+
+  // Variables used only if displaying the auth flow in a browser tab.
+  //
+  // Checks that the auth with browser tab is activated.
+  bool using_auth_with_browser_tab_ = false;
+  // WebContents used to initialize the authentication. It is not displayed
+  // and not owned by browser window. This WebContents is observed by
+  // `this`. When this value becomes nullptr, this means that the browser tab
+  // has taken ownership and the interactive tab was opened.
+  std::unique_ptr<content::WebContents> web_contents_;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc b/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
index b51c396..389c6fc 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
+++ b/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
@@ -7,10 +7,15 @@
 #include "base/strings/strcat.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
+#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
+#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
+#include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/keep_alive_registry/scoped_keep_alive.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/fenced_frame_test_util.h"
@@ -43,10 +48,14 @@
 
   void StartWebAuthFlow(
       const GURL& url,
-      WebAuthFlow::Partition partition = WebAuthFlow::LAUNCH_WEB_AUTH_FLOW) {
+      WebAuthFlow::Partition partition = WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
+      WebAuthFlow::Mode mode = WebAuthFlow::Mode::INTERACTIVE,
+      Profile* profile = nullptr) {
+    if (!profile)
+      profile = browser()->profile();
+
     web_auth_flow_ = std::make_unique<WebAuthFlow>(
-        &mock_web_auth_flow_delegate_, browser()->profile(), url,
-        WebAuthFlow::INTERACTIVE, partition);
+        &mock_web_auth_flow_delegate_, profile, url, mode, partition);
     web_auth_flow_->Start();
   }
 
@@ -64,52 +73,85 @@
   MockWebAuthFlowDelegate mock_web_auth_flow_delegate_;
 };
 
-IN_PROC_BROWSER_TEST_F(WebAuthFlowBrowserTest, OnAuthFlowURLChangeCalled) {
+class WebAuthFlowInBrowserTabParamBrowserTest
+    : public WebAuthFlowBrowserTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  WebAuthFlowInBrowserTabParamBrowserTest() {
+    scoped_feature_list_.InitWithFeatureState(kWebAuthFlowInBrowserTab,
+                                              use_tab_feature_enabled());
+  }
+
+  bool use_tab_feature_enabled() { return GetParam(); }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+                       OnAuthFlowURLChangeCalled) {
   const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
 
   // Observer for waiting until a navigation to a url has finished.
   content::TestNavigationObserver navigation_observer(auth_url);
   navigation_observer.StartWatchingNewWebContents();
 
-  StartWebAuthFlow(auth_url);
   // The delegate method OnAuthFlowURLChange should be called
   // by DidStartNavigation.
   EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
+  StartWebAuthFlow(auth_url);
 
   navigation_observer.WaitForNavigationFinished();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAuthFlowBrowserTest, OnAuthFlowFailureChangeCalled) {
+IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+                       OnAuthFlowFailureChangeCalled) {
   // Navigate to a url that doesn't exist.
   const GURL error_url = embedded_test_server()->GetURL("/error");
 
   content::TestNavigationObserver navigation_observer(error_url);
   navigation_observer.StartWatchingNewWebContents();
 
-  StartWebAuthFlow(error_url);
   // The delegate method OnAuthFlowFailure should be called
   // by DidFinishNavigation.
   EXPECT_CALL(mock(), OnAuthFlowFailure(WebAuthFlow::LOAD_FAILED));
+  StartWebAuthFlow(error_url);
 
   navigation_observer.WaitForNavigationFinished();
 }
 
+INSTANTIATE_TEST_CASE_P(
+    ,
+    WebAuthFlowInBrowserTabParamBrowserTest,
+    testing::Bool(),
+    [](const testing::TestParamInfo<
+        WebAuthFlowInBrowserTabParamBrowserTest::ParamType>& info) {
+      return base::StrCat(
+          {info.param ? "With" : "Without", "WebAuthFlowInBrowserTab"});
+    });
+
 class WebAuthFlowGuestPartitionParamTest
     : public WebAuthFlowBrowserTest,
       public testing::WithParamInterface<
           std::tuple<bool, WebAuthFlow::Partition>> {
  public:
   WebAuthFlowGuestPartitionParamTest() {
-    if (feature_enabled()) {
-      scoped_feature_list_.InitAndEnableFeature(
-          kPersistentStorageForWebAuthFlow);
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          kPersistentStorageForWebAuthFlow);
-    }
+    std::vector<base::test::FeatureRef> enabled_features;
+    std::vector<base::test::FeatureRef> disabled_features;
+
+    persist_storage_feature_enabled()
+        ? enabled_features.push_back(kPersistentStorageForWebAuthFlow)
+        : disabled_features.push_back(kPersistentStorageForWebAuthFlow);
+
+    // Explicitly disable the `kWebAuthFlowInBrowserTab` feature as it is
+    // incompatible with the Guest Partition tests and
+    // `kPersistentStorageForWebAuthFlow`.
+    disabled_features.push_back(kWebAuthFlowInBrowserTab);
+
+    scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
   }
 
-  bool feature_enabled() { return std::get<0>(GetParam()); }
+  bool persist_storage_feature_enabled() { return std::get<0>(GetParam()); }
 
   WebAuthFlow::Partition partition() { return std::get<1>(GetParam()); }
 
@@ -174,7 +216,8 @@
   // Read from the cookie store directly rather than execute a script on the
   // auth page because the page URL changes between test (test server doesn't
   // have a fixed port).
-  if (feature_enabled() && partition() == WebAuthFlow::LAUNCH_WEB_AUTH_FLOW) {
+  if (persist_storage_feature_enabled() &&
+      partition() == WebAuthFlow::LAUNCH_WEB_AUTH_FLOW) {
     ASSERT_EQ(1u, cookies.size());
     EXPECT_EQ("testCookie", cookies[0].Name());
     EXPECT_EQ("1", cookies[0].Value());
@@ -197,7 +240,8 @@
                ? "WebAuthFlow"
                : "GetAuthToken"});
     });
-class WebAuthFlowFencedFrameTest : public WebAuthFlowBrowserTest {
+class WebAuthFlowFencedFrameTest
+    : public WebAuthFlowInBrowserTabParamBrowserTest {
  public:
   content::test::FencedFrameTestHelper& fenced_frame_test_helper() {
     return fenced_frame_helper_;
@@ -207,7 +251,7 @@
   content::test::FencedFrameTestHelper fenced_frame_helper_;
 };
 
-IN_PROC_BROWSER_TEST_F(WebAuthFlowFencedFrameTest,
+IN_PROC_BROWSER_TEST_P(WebAuthFlowFencedFrameTest,
                        FencedFrameNavigationSuccess) {
   const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
 
@@ -218,9 +262,9 @@
       content::TestNavigationObserver::WaitEvent::kLoadStopped);
   navigation_observer.StartWatchingNewWebContents();
 
+  EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
   StartWebAuthFlow(auth_url);
 
-  EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
   navigation_observer.Wait();
   testing::Mock::VerifyAndClearExpectations(&mock());
 
@@ -234,7 +278,7 @@
       embedded_test_server()->GetURL("/fenced_frames/title1.html")));
 }
 
-IN_PROC_BROWSER_TEST_F(WebAuthFlowFencedFrameTest,
+IN_PROC_BROWSER_TEST_P(WebAuthFlowFencedFrameTest,
                        FencedFrameNavigationFailure) {
   const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
 
@@ -245,9 +289,9 @@
       content::TestNavigationObserver::WaitEvent::kLoadStopped);
   navigation_observer.StartWatchingNewWebContents();
 
+  EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
   StartWebAuthFlow(auth_url);
 
-  EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
   navigation_observer.Wait();
   testing::Mock::VerifyAndClearExpectations(&mock());
 
@@ -262,4 +306,107 @@
       embedded_test_server()->GetURL("/error"), net::Error::ERR_FAILED));
 }
 
+INSTANTIATE_TEST_CASE_P(,
+                        WebAuthFlowFencedFrameTest,
+                        testing::Bool(),
+                        [](const testing::TestParamInfo<
+                            WebAuthFlowFencedFrameTest::ParamType>& info) {
+                          return base::StrCat({info.param ? "With" : "Without",
+                                               "WebAuthFlowInBrowserTab"});
+                        });
+
+class WebAuthFlowWithBrowserTabBrowserTest : public WebAuthFlowBrowserTest {
+ public:
+  WebAuthFlowWithBrowserTabBrowserTest() {
+    scoped_feature_list_.InitAndEnableFeature(kWebAuthFlowInBrowserTab);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// This test is in two parts:
+// - First create a WebAuthFlow in interactive mode that will create a new tab
+// with the auth_url.
+// - Close the new created tab, simulating the user declining the consent by
+// closing the tab.
+//
+// These two tests are combined into one in order not to re-test the tab
+// creation twice.
+IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
+                       InteractiveNewTabCreatedWithAuthURL_ThenCloseTab) {
+  TabStripModel* tabs = browser()->tab_strip_model();
+  int initial_tab_count = tabs->count();
+
+  const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
+  content::TestNavigationObserver navigation_observer(auth_url);
+  navigation_observer.StartWatchingNewWebContents();
+
+  EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
+  StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
+                   WebAuthFlow::Mode::INTERACTIVE);
+
+  navigation_observer.Wait();
+
+  EXPECT_EQ(tabs->count(), initial_tab_count + 1);
+  EXPECT_EQ(tabs->GetActiveWebContents()->GetLastCommittedURL(), auth_url);
+
+  //---------------------------------------------------------------------
+  // Part of the test that closes the tab, simulating declining the consent.
+  //---------------------------------------------------------------------
+  EXPECT_CALL(mock(), OnAuthFlowFailure(WebAuthFlow::Failure::WINDOW_CLOSED));
+  tabs->CloseWebContentsAt(tabs->active_index(), 0);
+}
+
+IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
+                       InteractiveNoBrowser_WebAuthCreatesBrowserWithTab) {
+  Profile* profile = browser()->profile();
+  // Simulates an extension being opened, in order for the profile not to be
+  // added for destruction.
+  ScopedProfileKeepAlive profile_keep_alive(
+      profile, ProfileKeepAliveOrigin::kBackgroundMode);
+  ScopedKeepAlive keep_alive{KeepAliveOrigin::BROWSER,
+                             KeepAliveRestartOption::DISABLED};
+  CloseBrowserSynchronously(browser());
+  ASSERT_FALSE(chrome::FindBrowserWithProfile(profile));
+
+  const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
+  content::TestNavigationObserver navigation_observer(auth_url);
+  navigation_observer.StartWatchingNewWebContents();
+
+  EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
+  StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
+                   WebAuthFlow::Mode::INTERACTIVE, profile);
+
+  navigation_observer.Wait();
+
+  Browser* new_browser = chrome::FindBrowserWithProfile(profile);
+  EXPECT_TRUE(new_browser);
+  EXPECT_EQ(new_browser->tab_strip_model()
+                ->GetActiveWebContents()
+                ->GetLastCommittedURL(),
+            auth_url);
+}
+
+IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
+                       SilentNewTabNotCreated) {
+  TabStripModel* tabs = browser()->tab_strip_model();
+  int initial_tab_count = tabs->count();
+
+  const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
+  content::TestNavigationObserver navigation_observer(auth_url);
+  navigation_observer.StartWatchingNewWebContents();
+
+  EXPECT_CALL(mock(),
+              OnAuthFlowFailure(WebAuthFlow::Failure::INTERACTION_REQUIRED));
+  EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
+  StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
+                   WebAuthFlow::Mode::SILENT);
+
+  navigation_observer.Wait();
+
+  // Tab not created, tab count did not increase.
+  EXPECT_EQ(tabs->count(), initial_tab_count);
+}
+
 }  //  namespace extensions
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
index 796e4aac..1b5b84c0 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -222,7 +222,13 @@
 // events to the onStatusChange listener.  The test loads a page that toggles
 // fullscreen mode, using the Fullscreen Javascript API, in response to mouse
 // clicks.
-IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, FullscreenEvents) {
+#if BUILDFLAG(IS_MAC)
+// TODO(crbug.com/1392776): Flaky on Mac.
+#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
+#else
+#define MAYBE_FullscreenEvents FullscreenEvents
+#endif  // BUILDFLAG(IS_MAC)
+IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_FullscreenEvents) {
   AddExtensionToCommandLineAllowlist();
 
   ExtensionTestMessageListener capture_started("tab_capture_started");
diff --git a/chrome/browser/first_run/upgrade_util_win.cc b/chrome/browser/first_run/upgrade_util_win.cc
index 3dc6139..ffafc6a 100644
--- a/chrome/browser/first_run/upgrade_util_win.cc
+++ b/chrome/browser/first_run/upgrade_util_win.cc
@@ -39,7 +39,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/install_static/install_util.h"
-#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/app_command.h"
 #include "chrome/installer/util/util_constants.h"
 #include "components/prefs/pref_service.h"
 #include "ui/base/ui_base_switches.h"
@@ -81,8 +81,7 @@
   {
     TRACE_EVENT0("startup", "InvokeGoogleUpdateForRename LaunchCmdElevated");
     HRESULT hr = ipl->LaunchCmdElevated(
-        install_static::GetAppGuid(),
-        google_update::kRegRenameCmdField,
+        install_static::GetAppGuid(), installer::kCmdRenameChromeExe,
         ::GetCurrentProcessId(), &process_handle);
     if (FAILED(hr)) {
       TRACE_EVENT0("startup",
@@ -168,29 +167,16 @@
 
   // If this is a user-level install, directly launch a process to rename Chrome
   // executables. Obtain the command to launch the process from the registry.
-  base::win::RegKey key;
-  auto result =
-      key.Open(HKEY_CURRENT_USER, install_static::GetClientsKeyPath().c_str(),
-               KEY_QUERY_VALUE | KEY_WOW64_32KEY);
-  if (result != ERROR_SUCCESS) {
-    ::SetLastError(result);
-    PLOG(ERROR) << "Open Clients key failed";
+  installer::AppCommand rename_cmd(installer::kCmdRenameChromeExe, {});
+  if (!rename_cmd.Initialize(HKEY_CURRENT_USER))
     return false;
-  }
-
-  std::wstring rename_cmd;
-  result = key.ReadValue(google_update::kRegRenameCmdField, &rename_cmd);
-  if (result != ERROR_SUCCESS) {
-    ::SetLastError(result);
-    PLOG(ERROR) << "Read rename command failed";
-    return false;
-  }
 
   base::LaunchOptions options;
   options.wait = true;
   options.start_hidden = true;
   ::SetLastError(ERROR_SUCCESS);
-  base::Process process = base::LaunchProcess(rename_cmd, options);
+  base::Process process =
+      base::LaunchProcess(rename_cmd.command_line(), options);
   if (!process.IsValid()) {
     PLOG(ERROR) << "Launch rename process failed";
     return false;
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 95caac726..3b2a2cb5 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -978,11 +978,6 @@
     "This option enables high-quality, network-based voices in "
     "Select-to-speak.";
 
-const char kAccessibilityOSSettingsVisibilityName[] =
-    "Accessibility OS Settings Visibility";
-const char kAccessibilityOSSettingsVisibilityDescription[] =
-    "This option enables improvements in Accessibility OS Settings visibility.";
-
 const char kAccessibilityServiceName[] = "Experimental Accessibility Service";
 const char kAccessibilityServiceDescription[] =
     "This option enables the experimental Accessibility Service and runs some "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 94b0146..910d5bb 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -566,9 +566,6 @@
 extern const char kEnhancedNetworkVoicesName[];
 extern const char kEnhancedNetworkVoicesDescription[];
 
-extern const char kAccessibilityOSSettingsVisibilityName[];
-extern const char kAccessibilityOSSettingsVisibilityDescription[];
-
 extern const char kAccessibilityServiceName[];
 extern const char kAccessibilityServiceDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 0d391f6..14cfc93 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -247,6 +247,7 @@
     &kFoldableJankFix,
     &kGridTabSwitcherForTablets,
     &kHandleMediaIntents,
+    &kHideNonDisplayableAccountEmail,
     &kImmersiveUiMode,
     &kIncognitoReauthenticationForAndroid,
     &kIncognitoScreenshot,
@@ -777,6 +778,10 @@
              "HandleMediaIntents",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+BASE_FEATURE(kHideNonDisplayableAccountEmail,
+             "HideNonDisplayableAccountEmail",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 BASE_FEATURE(kImmersiveUiMode,
              "ImmersiveUiMode",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 0d13451..0afbb63b 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -96,6 +96,7 @@
 BASE_DECLARE_FEATURE(kFoldableJankFix);
 BASE_DECLARE_FEATURE(kGridTabSwitcherForTablets);
 BASE_DECLARE_FEATURE(kHandleMediaIntents);
+BASE_DECLARE_FEATURE(kHideNonDisplayableAccountEmail);
 BASE_DECLARE_FEATURE(kImmersiveUiMode);
 BASE_DECLARE_FEATURE(kIncognitoReauthenticationForAndroid);
 BASE_DECLARE_FEATURE(kIncognitoScreenshot);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 24457242..0531da2 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -341,6 +341,8 @@
     public static final String TANGIBLE_SYNC = "TangibleSync";
     public static final String GRID_TAB_SWITCHER_FOR_TABLETS = "GridTabSwitcherForTablets";
     public static final String HANDLE_MEDIA_INTENTS = "HandleMediaIntents";
+    public static final String HIDE_NON_DISPLAYABLE_ACCOUNT_EMAIL =
+            "HideNonDisplayableAccountEmail";
     public static final String HTTPS_FIRST_MODE = "HttpsOnlyMode";
     public static final String IMMERSIVE_UI_MODE = "ImmersiveUiMode";
     public static final String INCOGNITO_DOWNLOADS_WARNING = "IncognitoDownloadsWarning";
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index 979ae74..041d36e9 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "build/buildflag.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/buildflags.h"
 #include "chrome/browser/devtools/devtools_infobar_delegate.h"
 #include "chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h"
 #include "chrome/browser/extensions/api/messaging/incognito_connectability_infobar_delegate.h"
@@ -65,7 +66,7 @@
 #include "chrome/browser/ui/startup/default_browser_infobar_delegate.h"
 #endif
 
-#if BUILDFLAG(IS_MAC)
+#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER)
 #include "chrome/browser/ui/cocoa/keystone_infobar_delegate.h"
 #endif
 
@@ -279,7 +280,7 @@
       break;
 
     case IBD::KEYSTONE_PROMOTION_INFOBAR_DELEGATE_MAC:
-#if BUILDFLAG(IS_MAC)
+#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER)
       KeystonePromotionInfoBarDelegate::Create(GetWebContents());
 #else
       ADD_FAILURE() << "This infobar is not supported on this OS.";
diff --git a/chrome/browser/payments/android/payment_app_service_bridge_unittest.cc b/chrome/browser/payments/android/payment_app_service_bridge_unittest.cc
index 971b17ad..9c15e988 100644
--- a/chrome/browser/payments/android/payment_app_service_bridge_unittest.cc
+++ b/chrome/browser/payments/android/payment_app_service_bridge_unittest.cc
@@ -124,7 +124,6 @@
                               base::Unretained(&mock_callback)))
           ->GetWeakPtrForTest();
 
-  EXPECT_TRUE(bridge->SkipCreatingNativePaymentApps());
   EXPECT_EQ(web_contents_, bridge->GetWebContents());
   EXPECT_EQ(top_origin_, bridge->GetTopOrigin());
   EXPECT_EQ(frame_origin_, bridge->GetFrameOrigin());
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.ts b/chrome/browser/resources/settings/a11y_page/a11y_page.ts
index afad239..b796241 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.ts
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.ts
@@ -182,13 +182,7 @@
 
   // <if expr="is_chromeos">
   private onManageSystemAccessibilityFeaturesTap_() {
-    if (loadTimeData.valueExists(
-            'isAccessibilityOSSettingsVisibilityEnabled') &&
-        loadTimeData.getBoolean('isAccessibilityOSSettingsVisibilityEnabled')) {
-      window.location.href = 'chrome://os-settings/osAccessibility';
-    } else {
-      window.location.href = 'chrome://os-settings/manageAccessibility';
-    }
+    window.location.href = 'chrome://os-settings/osAccessibility';
   }
   // </if>
 
diff --git a/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.ts b/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.ts
index 4f730e2..91cef3f 100644
--- a/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.ts
+++ b/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.ts
@@ -25,10 +25,9 @@
 import {loadTimeData} from '../../i18n_setup.js';
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
 import {PrefsMixin, PrefsMixinInterface} from '../../prefs/prefs_mixin.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './date_time_page.html.js';
 import {TimeZoneBrowserProxy, TimeZoneBrowserProxyImpl} from './timezone_browser_proxy.js';
@@ -37,12 +36,12 @@
     mixinBehaviors(
         [
           DeepLinkingBehavior,
-          RouteObserverBehavior,
         ],
-        PrefsMixin(I18nMixin(WebUiListenerMixin(PolymerElement)))) as {
+        RouteObserverMixin(
+            PrefsMixin(I18nMixin(WebUiListenerMixin(PolymerElement))))) as {
       new (): PolymerElement & WebUiListenerMixinInterface &
           I18nMixinInterface & PrefsMixinInterface &
-          DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface & DeepLinkingBehaviorInterface,
     };
 
 class SettingsDateTimePageElement extends SettingsDateTimePageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.ts b/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.ts
index ab2066be..0916cef 100644
--- a/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.ts
+++ b/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.ts
@@ -20,10 +20,9 @@
 import {SettingsDropdownMenuElement} from '../../controls/settings_dropdown_menu.js';
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
 import {PrefsMixin, PrefsMixinInterface} from '../../prefs/prefs_mixin.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {TimeZoneAutoDetectMethod} from './date_time_types.js';
 import {TimeZoneBrowserProxy, TimeZoneBrowserProxyImpl} from './timezone_browser_proxy.js';
@@ -41,12 +40,11 @@
     mixinBehaviors(
         [
           DeepLinkingBehavior,
-          RouteObserverBehavior,
         ],
-        PrefsMixin(WebUiListenerMixin(PolymerElement))) as {
+        RouteObserverMixin(PrefsMixin(WebUiListenerMixin(PolymerElement)))) as {
       new (): PolymerElement & WebUiListenerMixinInterface &
-          PrefsMixinInterface & DeepLinkingBehaviorInterface &
-          RouteObserverBehaviorInterface,
+          PrefsMixinInterface & RouteObserverMixinInterface &
+          DeepLinkingBehaviorInterface,
     };
 
 class TimezoneSubpageElement extends TimezoneSubpageElementBase {
@@ -87,7 +85,7 @@
   }
 
   /**
-   * RouteObserverBehavior
+   * RouteObserverMixin
    * Called when the timezone subpage is hit. Child accounts need parental
    * approval to modify their timezone, this method starts this process on the
    * C++ side, and timezone setting will be disable. Once it is complete the
diff --git a/chrome/browser/resources/settings/chromeos/device_page/device_page.ts b/chrome/browser/resources/settings/chromeos/device_page/device_page.ts
index 4f058a2a..f223edd7 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/device_page.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/device_page.ts
@@ -24,11 +24,10 @@
 import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {WebUiListenerMixin, WebUiListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {Router} from '../../router.js';
+import {RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './device_page.html.js';
 import {DevicePageBrowserProxy, DevicePageBrowserProxyImpl} from './device_page_browser_proxy.js';
@@ -39,12 +38,12 @@
   };
 }
 
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
 const SettingsDevicePageElementBase =
-    mixinBehaviors(
-        [RouteObserverBehavior],
-        I18nMixin(WebUiListenerMixin(PolymerElement))) as {
+    RouteObserverMixin(I18nMixin(WebUiListenerMixin(PolymerElement))) as {
       new (): PolymerElement & I18nMixinInterface &
-          WebUiListenerMixinInterface & RouteObserverBehaviorInterface,
+          WebUiListenerMixinInterface & RouteObserverMixinInterface,
     };
 
 class SettingsDevicePageElement extends SettingsDevicePageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/device_page/pointers.ts b/chrome/browser/resources/settings/chromeos/device_page/pointers.ts
index d1291b7..78622939 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/pointers.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/pointers.ts
@@ -20,19 +20,18 @@
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
 import {PrefsMixin, PrefsMixinInterface} from '../../prefs/prefs_mixin.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './pointers.html.js';
 
 const SettingsPointersElementBase =
     mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior],
-        PrefsMixin(PolymerElement)) as {
+        [DeepLinkingBehavior],
+        RouteObserverMixin(PrefsMixin(PolymerElement))) as {
       new (): PolymerElement & PrefsMixinInterface &
-          DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface & DeepLinkingBehaviorInterface,
     };
 
 class SettingsPointersElement extends SettingsPointersElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/device_page/stylus.ts b/chrome/browser/resources/settings/chromeos/device_page/stylus.ts
index c3c9ba9..3a2ea1b 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/stylus.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/stylus.ts
@@ -20,12 +20,11 @@
 import {microTask, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {assertExists} from '../assert_extras.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {recordSettingChange} from '../metrics_recorder.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {DevicePageBrowserProxy, DevicePageBrowserProxyImpl, NoteAppInfo, NoteAppLockScreenSupport} from './device_page_browser_proxy.js';
 import {getTemplate} from './stylus.html.js';
@@ -40,10 +39,10 @@
     'collection/promotion_30023cb_stylus_apps';
 
 const SettingsStylusElementBase =
-    mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior], PolymerElement) as {
+    mixinBehaviors([DeepLinkingBehavior], RouteObserverMixin(PolymerElement)) as
+    {
       new (): PolymerElement & DeepLinkingBehaviorInterface &
-          RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface,
     };
 
 class SettingsStylusElement extends SettingsStylusElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.ts b/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.ts
index 36a7bbd2..4b5d277 100644
--- a/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.ts
+++ b/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.ts
@@ -23,12 +23,11 @@
 import {SettingsToggleButtonElement} from '../../controls/settings_toggle_button.js';
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
 import {PrefsMixin, PrefsMixinInterface} from '../../prefs/prefs_mixin.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {cast, castExists} from '../assert_extras.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {recordSettingChange} from '../metrics_recorder.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {GoogleAssistantBrowserProxy, GoogleAssistantBrowserProxyImpl} from './google_assistant_browser_proxy.js';
 import {getTemplate} from './google_assistant_page.html.js';
@@ -67,12 +66,12 @@
     mixinBehaviors(
         [
           DeepLinkingBehavior,
-          RouteObserverBehavior,
         ],
-        PrefsMixin(WebUiListenerMixin(I18nMixin(PolymerElement)))) as {
+        RouteObserverMixin(
+            PrefsMixin(WebUiListenerMixin(I18nMixin(PolymerElement))))) as {
       new (): PolymerElement & I18nMixinInterface &
           WebUiListenerMixinInterface & PrefsMixinInterface &
-          DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface & DeepLinkingBehaviorInterface,
     };
 
 class SettingsGoogleAssistantPageElement extends
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js
index b824ab1..b063015b 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.js
@@ -237,15 +237,6 @@
         },
       },
 
-      /** @protected */
-      isAccessibilityOSSettingsVisibilityEnabled_: {
-        type: Boolean,
-        value() {
-          return loadTimeData.getBoolean(
-              'isAccessibilityOSSettingsVisibilityEnabled');
-        },
-      },
-
       /**
        * Whether the user is in kiosk mode.
        * @protected
@@ -426,8 +417,7 @@
     /** @private {!DevicePageBrowserProxy} */
     this.deviceBrowserProxy_ = DevicePageBrowserProxyImpl.getInstance();
 
-    if (loadTimeData.getBoolean('isAccessibilityOSSettingsVisibilityEnabled') &&
-        !this.isKioskModeActive_) {
+    if (!this.isKioskModeActive_) {
       this.redirectToNewA11ySettings();
     }
   }
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
index e97a7d8d..ddb947f 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.html
@@ -21,51 +21,40 @@
         deep-link-focus-id$="[[Setting.kA11yQuickSettings]]">
     </settings-toggle-button>
     <div class="hr" hidden="[[isKioskModeActive_]]"></div>
-    <template is="dom-if"
-        if="[[isAccessibilityOSSettingsVisibilityEnabled_]]">
-      <cr-link-row id="text-to-speech-page-trigger"
-          label="$i18n{textToSpeechLinkTitle}"
-          on-click="onTextToSpeechTap_"
-          sub-label="$i18n{textToSpeechLinkDescription}"
-          role-description="$i18n{subpageArrowRoleDescription}">
-      </cr-link-row>
-      <div class="hr"></div>
-      <cr-link-row id="display-and-magnification-page-trigger"
-          label="$i18n{displayAndMagnificationLinkTitle}"
-          on-click="onDisplayAndMagnificationTap_"
-          sub-label="$i18n{displayAndMagnificationLinkDescription}"
-          role-description="$i18n{subpageArrowRoleDescription}">
-      </cr-link-row>
-      <div class="hr"></div>
-      <cr-link-row id="keyboard-and-text-input-page-trigger"
-          label="$i18n{keyboardAndTextInputLinkTitle}"
-          on-click="onKeyboardAndTextInputTap_"
-          sub-label="$i18n{keyboardAndTextInputLinkDescription}"
-          role-description="$i18n{subpageArrowRoleDescription}">
-      </cr-link-row>
-      <div class="hr"></div>
-      <cr-link-row id="cursor-and-touchpad-page-trigger"
-          label="$i18n{cursorAndTouchpadLinkTitle}"
-          on-click="onCursorAndTouchpadTap_"
-          sub-label="$i18n{cursorAndTouchpadLinkDescription}"
-          role-description="$i18n{subpageArrowRoleDescription}">
-      </cr-link-row>
-      <div class="hr"></div>
-      <cr-link-row id="audio-and-captions-page-trigger"
-          label="$i18n{audioAndCaptionsLinkTitle}"
-          on-click="onAudioAndCaptionsTap_"
-          sub-label="$i18n{audioAndCaptionsLinkDescription}"
-          role-description="$i18n{subpageArrowRoleDescription}">
-      </cr-link-row>
-    </template>
-    <template is="dom-if" if="[[!isAccessibilityOSSettingsVisibilityEnabled_]]">
-      <cr-link-row id="subpage-trigger"
-        label="$i18n{manageAccessibilityFeatures}"
-        on-click="onManageAccessibilityFeaturesTap_"
-        sub-label="$i18n{moreFeaturesLinkDescription}"
+    <cr-link-row id="text-to-speech-page-trigger"
+        label="$i18n{textToSpeechLinkTitle}"
+        on-click="onTextToSpeechTap_"
+        sub-label="$i18n{textToSpeechLinkDescription}"
         role-description="$i18n{subpageArrowRoleDescription}">
-      </cr-link-row>
-    </template>
+    </cr-link-row>
+    <div class="hr"></div>
+    <cr-link-row id="display-and-magnification-page-trigger"
+        label="$i18n{displayAndMagnificationLinkTitle}"
+        on-click="onDisplayAndMagnificationTap_"
+        sub-label="$i18n{displayAndMagnificationLinkDescription}"
+        role-description="$i18n{subpageArrowRoleDescription}">
+    </cr-link-row>
+    <div class="hr"></div>
+    <cr-link-row id="keyboard-and-text-input-page-trigger"
+        label="$i18n{keyboardAndTextInputLinkTitle}"
+        on-click="onKeyboardAndTextInputTap_"
+        sub-label="$i18n{keyboardAndTextInputLinkDescription}"
+        role-description="$i18n{subpageArrowRoleDescription}">
+    </cr-link-row>
+    <div class="hr"></div>
+    <cr-link-row id="cursor-and-touchpad-page-trigger"
+        label="$i18n{cursorAndTouchpadLinkTitle}"
+        on-click="onCursorAndTouchpadTap_"
+        sub-label="$i18n{cursorAndTouchpadLinkDescription}"
+        role-description="$i18n{subpageArrowRoleDescription}">
+    </cr-link-row>
+    <div class="hr"></div>
+    <cr-link-row id="audio-and-captions-page-trigger"
+        label="$i18n{audioAndCaptionsLinkTitle}"
+        on-click="onAudioAndCaptionsTap_"
+        sub-label="$i18n{audioAndCaptionsLinkDescription}"
+        role-description="$i18n{subpageArrowRoleDescription}">
+    </cr-link-row>
     <template is="dom-if"
         if="[[shouldShowAdditionalFeaturesLink_(isKioskModeActive_, isGuest_)]]">
       <cr-link-row
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.ts b/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.ts
index 7bfcf3c8..f7c39ed 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/os_a11y_page.ts
@@ -86,14 +86,6 @@
         value: false,
       },
 
-      isAccessibilityOSSettingsVisibilityEnabled_: {
-        type: Boolean,
-        value() {
-          return loadTimeData.getBoolean(
-              'isAccessibilityOSSettingsVisibilityEnabled');
-        },
-      },
-
       /**
        * Whether Select-to-speak page migration is enabled.
        */
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts
index 1cf29ada..5245130 100644
--- a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts
+++ b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts
@@ -26,11 +26,10 @@
 import {loadTimeData} from '../../i18n_setup.js';
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
 import {PrefsMixin, PrefsMixinInterface} from '../../prefs/prefs_mixin.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {castExists} from '../assert_extras.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, browserChannelToI18nId, ChannelInfo, VersionInfo} from './about_page_browser_proxy.js';
 import {getTemplate} from './detailed_build_info.html.js';
@@ -47,12 +46,12 @@
     mixinBehaviors(
         [
           DeepLinkingBehavior,
-          RouteObserverBehavior,
         ],
-        PrefsMixin(I18nMixin(WebUiListenerMixin(PolymerElement)))) as {
+        RouteObserverMixin(
+            PrefsMixin(I18nMixin(WebUiListenerMixin(PolymerElement))))) as {
       new (): PolymerElement & WebUiListenerMixinInterface &
           I18nMixinInterface & PrefsMixinInterface &
-          DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface & DeepLinkingBehaviorInterface,
     };
 
 class SettingsDetailedBuildInfoElement extends SettingsDetailedBuildInfoBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.ts b/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.ts
index 0643230..327a812e 100644
--- a/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.ts
@@ -16,18 +16,17 @@
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_files_page.html.js';
 
 const OsSettingsFilesPageElementBase =
-    mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior], PolymerElement) as {
-      new (): DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface &
-          PolymerElement,
+    mixinBehaviors([DeepLinkingBehavior], RouteObserverMixin(PolymerElement)) as
+    {
+      new (): PolymerElement & RouteObserverMixinInterface &
+          DeepLinkingBehaviorInterface,
     };
 
 class OsSettingsFilesPageElement extends OsSettingsFilesPageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.ts b/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.ts
index 7b5a618..9202a6e 100644
--- a/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.ts
@@ -11,18 +11,18 @@
 import '../../settings_shared.css.js';
 import '../../settings_vars.css.js';
 
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './smb_shares_page.html.js';
 
-const SettingsSmbSharesPageElementBase =
-    mixinBehaviors([RouteObserverBehavior], PolymerElement) as {
-      new (): PolymerElement & RouteObserverBehaviorInterface,
-    };
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
+const SettingsSmbSharesPageElementBase = RouteObserverMixin(PolymerElement) as {
+  new (): PolymerElement & RouteObserverMixinInterface,
+};
 
 class SettingsSmbSharesPageElement extends SettingsSmbSharesPageElementBase {
   static get is() {
@@ -51,7 +51,7 @@
   private showAddSmbDialog_: boolean;
 
   /**
-   * Overridden from RouteObserverBehavior.
+   * Overridden from RouteObserverMixin.
    */
   override currentRouteChanged(route: Route) {
     if (route === routes.SMB_SHARES) {
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.ts b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.ts
index d6248cf..46042da 100644
--- a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.ts
@@ -16,10 +16,9 @@
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_reset_page.html.js';
 
@@ -30,10 +29,10 @@
 }
 
 const OsSettingsResetPageElementBase =
-    mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior], PolymerElement) as {
+    mixinBehaviors([DeepLinkingBehavior], RouteObserverMixin(PolymerElement)) as
+    {
       new (): PolymerElement & DeepLinkingBehaviorInterface &
-          RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface,
     };
 
 class OsSettingsResetPageElement extends OsSettingsResetPageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_route.js b/chrome/browser/resources/settings/chromeos/os_route.js
index f95ce9b..81cb258 100644
--- a/chrome/browser/resources/settings/chromeos/os_route.js
+++ b/chrome/browser/resources/settings/chromeos/os_route.js
@@ -201,52 +201,48 @@
         Subpage.kPluginVmUsbPreferences);
   }
 
-  // Accessibility section, listed in Basic, if feature enabled.
-  if (loadTimeData.valueExists('isAccessibilityOSSettingsVisibilityEnabled') &&
-      loadTimeData.getBoolean('isAccessibilityOSSettingsVisibilityEnabled')) {
-    r.OS_ACCESSIBILITY = createSection(
-        r.BASIC, routesMojomWebui.ACCESSIBILITY_SECTION_PATH,
-        Section.kAccessibility);
-    r.MANAGE_ACCESSIBILITY = createSubpage(
-        r.OS_ACCESSIBILITY, routesMojomWebui.MANAGE_ACCESSIBILITY_SUBPAGE_PATH,
-        Subpage.kManageAccessibility);
-    r.A11Y_TEXT_TO_SPEECH = createSubpage(
-        r.OS_ACCESSIBILITY, routesMojomWebui.TEXT_TO_SPEECH_PAGE_PATH,
-        Subpage.kTextToSpeechPage);
-    r.A11Y_DISPLAY_AND_MAGNIFICATION = createSubpage(
-        r.OS_ACCESSIBILITY,
-        routesMojomWebui.DISPLAY_AND_MAGNIFICATION_SUBPAGE_PATH,
-        Subpage.kDisplayAndMagnification);
-    r.A11Y_KEYBOARD_AND_TEXT_INPUT = createSubpage(
-        r.OS_ACCESSIBILITY,
-        routesMojomWebui.KEYBOARD_AND_TEXT_INPUT_SUBPAGE_PATH,
-        Subpage.kKeyboardAndTextInput);
-    r.A11Y_CURSOR_AND_TOUCHPAD = createSubpage(
-        r.OS_ACCESSIBILITY, routesMojomWebui.CURSOR_AND_TOUCHPAD_SUBPAGE_PATH,
-        Subpage.kCursorAndTouchpad);
-    r.A11Y_AUDIO_AND_CAPTIONS = createSubpage(
-        r.OS_ACCESSIBILITY, routesMojomWebui.AUDIO_AND_CAPTIONS_SUBPAGE_PATH,
-        Subpage.kAudioAndCaptions);
-    if (loadTimeData.valueExists(
-            'isAccessibilitySelectToSpeakPageMigrationEnabled') &&
-        loadTimeData.getBoolean(
-            'isAccessibilitySelectToSpeakPageMigrationEnabled')) {
-      r.A11Y_SELECT_TO_SPEAK = createSubpage(
-          r.A11Y_TEXT_TO_SPEECH, routesMojomWebui.SELECT_TO_SPEAK_SUBPAGE_PATH,
-          Subpage.kSelectToSpeak);
-    }
-    r.MANAGE_TTS_SETTINGS = createSubpage(
-        loadTimeData.getBoolean('isKioskModeActive') ? r.MANAGE_ACCESSIBILITY :
-                                                       r.A11Y_TEXT_TO_SPEECH,
-        routesMojomWebui.TEXT_TO_SPEECH_SUBPAGE_PATH, Subpage.kTextToSpeech);
-    r.MANAGE_SWITCH_ACCESS_SETTINGS = createSubpage(
-        r.A11Y_KEYBOARD_AND_TEXT_INPUT,
-        routesMojomWebui.SWITCH_ACCESS_OPTIONS_SUBPAGE_PATH,
-        Subpage.kSwitchAccessOptions);
-    r.MANAGE_CAPTION_SETTINGS = createSubpage(
-        r.MANAGE_ACCESSIBILITY, routesMojomWebui.CAPTIONS_SUBPAGE_PATH,
-        Subpage.kCaptions);
+  // Accessibility section.
+  r.OS_ACCESSIBILITY = createSection(
+      r.BASIC, routesMojomWebui.ACCESSIBILITY_SECTION_PATH,
+      Section.kAccessibility);
+  r.MANAGE_ACCESSIBILITY = createSubpage(
+      r.OS_ACCESSIBILITY, routesMojomWebui.MANAGE_ACCESSIBILITY_SUBPAGE_PATH,
+      Subpage.kManageAccessibility);
+  r.A11Y_TEXT_TO_SPEECH = createSubpage(
+      r.OS_ACCESSIBILITY, routesMojomWebui.TEXT_TO_SPEECH_PAGE_PATH,
+      Subpage.kTextToSpeechPage);
+  r.A11Y_DISPLAY_AND_MAGNIFICATION = createSubpage(
+      r.OS_ACCESSIBILITY,
+      routesMojomWebui.DISPLAY_AND_MAGNIFICATION_SUBPAGE_PATH,
+      Subpage.kDisplayAndMagnification);
+  r.A11Y_KEYBOARD_AND_TEXT_INPUT = createSubpage(
+      r.OS_ACCESSIBILITY, routesMojomWebui.KEYBOARD_AND_TEXT_INPUT_SUBPAGE_PATH,
+      Subpage.kKeyboardAndTextInput);
+  r.A11Y_CURSOR_AND_TOUCHPAD = createSubpage(
+      r.OS_ACCESSIBILITY, routesMojomWebui.CURSOR_AND_TOUCHPAD_SUBPAGE_PATH,
+      Subpage.kCursorAndTouchpad);
+  r.A11Y_AUDIO_AND_CAPTIONS = createSubpage(
+      r.OS_ACCESSIBILITY, routesMojomWebui.AUDIO_AND_CAPTIONS_SUBPAGE_PATH,
+      Subpage.kAudioAndCaptions);
+  if (loadTimeData.valueExists(
+          'isAccessibilitySelectToSpeakPageMigrationEnabled') &&
+      loadTimeData.getBoolean(
+          'isAccessibilitySelectToSpeakPageMigrationEnabled')) {
+    r.A11Y_SELECT_TO_SPEAK = createSubpage(
+        r.A11Y_TEXT_TO_SPEECH, routesMojomWebui.SELECT_TO_SPEAK_SUBPAGE_PATH,
+        Subpage.kSelectToSpeak);
   }
+  r.MANAGE_TTS_SETTINGS = createSubpage(
+      loadTimeData.getBoolean('isKioskModeActive') ? r.MANAGE_ACCESSIBILITY :
+                                                     r.A11Y_TEXT_TO_SPEECH,
+      routesMojomWebui.TEXT_TO_SPEECH_SUBPAGE_PATH, Subpage.kTextToSpeech);
+  r.MANAGE_SWITCH_ACCESS_SETTINGS = createSubpage(
+      r.A11Y_KEYBOARD_AND_TEXT_INPUT,
+      routesMojomWebui.SWITCH_ACCESS_OPTIONS_SUBPAGE_PATH,
+      Subpage.kSwitchAccessOptions);
+  r.MANAGE_CAPTION_SETTINGS = createSubpage(
+      r.MANAGE_ACCESSIBILITY, routesMojomWebui.CAPTIONS_SUBPAGE_PATH,
+      Subpage.kCaptions);
 
   // Crostini section.
   r.CROSTINI = createSection(
@@ -364,27 +360,6 @@
       r.OS_PRINTING, routesMojomWebui.PRINTING_DETAILS_SUBPAGE_PATH,
       Subpage.kPrintingDetails);
 
-  // Accessibility section, listed in Advanced, if feature disabled.
-  if (!loadTimeData.valueExists('isAccessibilityOSSettingsVisibilityEnabled') ||
-      !loadTimeData.getBoolean('isAccessibilityOSSettingsVisibilityEnabled')) {
-    r.OS_ACCESSIBILITY = createSection(
-        r.ADVANCED, routesMojomWebui.ACCESSIBILITY_SECTION_PATH,
-        Section.kAccessibility);
-    r.MANAGE_ACCESSIBILITY = createSubpage(
-        r.OS_ACCESSIBILITY, routesMojomWebui.MANAGE_ACCESSIBILITY_SUBPAGE_PATH,
-        Subpage.kManageAccessibility);
-    r.MANAGE_TTS_SETTINGS = createSubpage(
-        r.MANAGE_ACCESSIBILITY, routesMojomWebui.TEXT_TO_SPEECH_SUBPAGE_PATH,
-        Subpage.kTextToSpeech);
-    r.MANAGE_SWITCH_ACCESS_SETTINGS = createSubpage(
-        r.MANAGE_ACCESSIBILITY,
-        routesMojomWebui.SWITCH_ACCESS_OPTIONS_SUBPAGE_PATH,
-        Subpage.kSwitchAccessOptions);
-    r.MANAGE_CAPTION_SETTINGS = createSubpage(
-        r.MANAGE_ACCESSIBILITY, routesMojomWebui.CAPTIONS_SUBPAGE_PATH,
-        Subpage.kCaptions);
-  }
-
   // Reset section.
   if (loadTimeData.valueExists('allowPowerwash') &&
       loadTimeData.getBoolean('allowPowerwash')) {
diff --git a/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.ts b/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.ts
index 4470b02..f7656243 100644
--- a/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.ts
@@ -27,19 +27,18 @@
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_search_page.html.js';
 
 const OsSettingsSearchPageElementBase =
     mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior],
-        I18nMixin(PolymerElement)) as {
+        [DeepLinkingBehavior], RouteObserverMixin(I18nMixin(PolymerElement))) as
+    {
       new (): PolymerElement & I18nMixinInterface &
-          DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface & DeepLinkingBehaviorInterface,
     };
 
 class OsSettingsSearchPageElement extends OsSettingsSearchPageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_search_page/search_subpage.ts b/chrome/browser/resources/settings/chromeos/os_search_page/search_subpage.ts
index 05234ee9..4d9ed40 100644
--- a/chrome/browser/resources/settings/chromeos/os_search_page/search_subpage.ts
+++ b/chrome/browser/resources/settings/chromeos/os_search_page/search_subpage.ts
@@ -26,20 +26,19 @@
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
 import {PrefsMixin, PrefsMixinInterface} from '../../prefs/prefs_mixin.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {castExists} from '../assert_extras.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './search_subpage.html.js';
 
 const SettingsSearchSubpageElementBase =
     mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior],
-        PrefsMixin(I18nMixin(PolymerElement))) as {
+        [DeepLinkingBehavior],
+        RouteObserverMixin(PrefsMixin(I18nMixin(PolymerElement)))) as {
       new (): PolymerElement & I18nMixinInterface & PrefsMixinInterface &
-          DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface & DeepLinkingBehaviorInterface,
     };
 
 class SettingsSearchSubpageElement extends SettingsSearchSubpageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.ts b/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.ts
index f372cc3..7341116 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.ts
@@ -17,14 +17,13 @@
 import '../../settings_shared.css.js';
 import '../../settings_vars.css.js';
 
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../../i18n_setup.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {assertExists} from '../assert_extras.js';
 import {OSPageVisibility} from '../os_page_visibility.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_settings_main.html.js';
 
@@ -39,10 +38,11 @@
   };
 }
 
-const OsSettingsMainElementBase =
-    mixinBehaviors([RouteObserverBehavior], PolymerElement) as {
-      new (): PolymerElement & RouteObserverBehaviorInterface,
-    };
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
+const OsSettingsMainElementBase = RouteObserverMixin(PolymerElement) as {
+  new (): PolymerElement & RouteObserverMixinInterface,
+};
 
 class OsSettingsMainElement extends OsSettingsMainElementBase {
   static get is() {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
index fdd226f..9957dd4 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
@@ -183,12 +183,10 @@
     <iron-icon icon="os-settings:apps"></iron-icon>
     $i18n{appsPageTitle}
   </a>
-  <template is="dom-if" if="[[isAccessibilityOSSettingsVisibilityEnabled_]]">
-    <a href="/osAccessibility" class="item">
-      <iron-icon icon="os-settings:accessibility"></iron-icon>
-      $i18n{a11yPageTitle}
-    </a>
-  </template>
+  <a href="/osAccessibility" class="item">
+    <iron-icon icon="os-settings:accessibility"></iron-icon>
+    $i18n{a11yPageTitle}
+  </a>
   <cr-button id="advancedButton"
       aria-expanded$="[[boolToString_(advancedOpened)]]"
       on-click="onAdvancedButtonToggle_">
@@ -219,12 +217,6 @@
         <iron-icon icon="os-settings:developer-tags"></iron-icon>
         $i18n{crostiniPageTitle}
       </a>
-      <template is="dom-if" if="[[!isAccessibilityOSSettingsVisibilityEnabled_]]">
-        <a href="/osAccessibility" class="item">
-          <iron-icon icon="os-settings:accessibility"></iron-icon>
-          $i18n{a11yPageTitle}
-        </a>
-      </template>
       <a id="osReset" href="/osReset" hidden="[[!showReset]]" class="item">
         <iron-icon icon="os-settings:restore"></iron-icon>
         $i18n{resetPageTitle}
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.ts b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.ts
index d6aea08..3e0f71f 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.ts
@@ -17,12 +17,11 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
 import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {castExists} from '../assert_extras.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_settings_menu.html.js';
 
@@ -34,10 +33,11 @@
   };
 }
 
-const OsSettingsMenuElementBase =
-    mixinBehaviors([RouteObserverBehavior], PolymerElement) as {
-      new (): PolymerElement & RouteObserverBehaviorInterface,
-    };
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
+const OsSettingsMenuElementBase = RouteObserverMixin(PolymerElement) as {
+  new (): PolymerElement & RouteObserverMixinInterface,
+};
 
 class OsSettingsMenuElement extends OsSettingsMenuElementBase {
   static get is() {
@@ -65,18 +65,6 @@
         readOnly: true,
       },
 
-      /**
-       * Whether Accessibility OS Settings visibility improvements are enabled.
-       */
-      isAccessibilityOSSettingsVisibilityEnabled_: {
-        type: Boolean,
-        readOnly: true,
-        value() {
-          return loadTimeData.getBoolean(
-              'isAccessibilityOSSettingsVisibilityEnabled');
-        },
-      },
-
       showCrostini: Boolean,
 
       showStartup: Boolean,
@@ -93,7 +81,6 @@
   showReset: boolean;
   showKerberosSection: boolean;
   private isGuestMode_: boolean;
-  private isAccessibilityOSSettingsVisibilityEnabled_: boolean;
 
   override currentRouteChanged(newRoute: Route) {
     const urlSearchQuery =
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html
index 52e338f..ada1d9d7 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html
@@ -185,13 +185,11 @@
           show-startup="[[showStartup]]">
       </os-settings-apps-page>
     </settings-section>
-    <template is="dom-if" if="[[isAccessibilityOSSettingsVisibilityEnabled_]]">
-      <settings-section page-title="$i18n{a11yPageTitle}"
-          section="osAccessibility">
-        <os-settings-a11y-page prefs="{{prefs}}">
-        </os-settings-a11y-page>
-      </settings-section>
-    </template>
+    <settings-section page-title="$i18n{a11yPageTitle}"
+        section="osAccessibility">
+      <os-settings-a11y-page prefs="{{prefs}}">
+      </os-settings-a11y-page>
+    </settings-section>
   </div>
 </template>
 
@@ -241,13 +239,6 @@
             show-crostini="[[showCrostini]]">
         </settings-crostini-page>
       </settings-section>
-      <template is="dom-if" if="[[!isAccessibilityOSSettingsVisibilityEnabled_]]">
-        <settings-section page-title="$i18n{a11yPageTitle}"
-            section="osAccessibility">
-          <os-settings-a11y-page prefs="{{prefs}}">
-          </os-settings-a11y-page>
-        </settings-section>
-      </template>
       <template is="dom-if" if="[[showReset]]">
         <settings-section page-title="$i18n{resetPageTitle}"
             section="osReset">
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.ts b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.ts
index 9fcceae6..cf9a79b2 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.ts
@@ -91,18 +91,6 @@
       },
 
       /**
-       * Whether Accessibility OS Settings visibility improvements are enabled.
-       */
-      isAccessibilityOSSettingsVisibilityEnabled_: {
-        type: Boolean,
-        readOnly: true,
-        value() {
-          return loadTimeData.getBoolean(
-              'isAccessibilityOSSettingsVisibilityEnabled');
-        },
-      },
-
-      /**
        * Dictionary defining page visibility.
        */
       pageVisibility: {
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 c4cf2b85f..08ead04e 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
@@ -22,23 +22,22 @@
 import '../../prefs/prefs.js';
 import '../../settings_vars.css.js';
 
-import {CrContainerShadowBehavior} from 'chrome://resources/ash/common/cr_container_shadow_behavior.js';
+import {CrContainerShadowMixin, CrContainerShadowMixinInterface} from 'chrome://resources/cr_elements/cr_container_shadow_mixin.js';
 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_ts.js';
-import {Debouncer, DomIf, microTask, mixinBehaviors, PolymerElement, timeOut} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {Debouncer, DomIf, microTask, PolymerElement, timeOut} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../../i18n_setup.js';
 import {SettingsPrefsElement} from '../../prefs/prefs.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {castExists} from '../assert_extras.js';
 import {setGlobalScrollTarget} from '../global_scroll_target_behavior.js';
 import {recordClick, recordNavigation, recordPageBlur, recordPageFocus, recordSettingChange} from '../metrics_recorder.js';
 import {OSPageVisibility, osPageVisibility} from '../os_page_visibility.js';
 import {OsToolbarElement} from '../os_toolbar/os_toolbar.js';
 import {PrefToSettingMetricConverter} from '../pref_to_setting_metric_converter.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_settings_ui.html.js';
 
@@ -72,17 +71,16 @@
   };
 }
 
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
 const OsSettingsUiElementBase =
-    mixinBehaviors(
-        [
-          CrContainerShadowBehavior,
-          // Calls currentRouteChanged() in attached(),so ensure other behaviors
-          // run their attached() first.
-          RouteObserverBehavior,
-        ],
-        FindShortcutMixin(PolymerElement)) as {
-      new (): PolymerElement & CrContainerShadowBehavior &
-          FindShortcutMixinInterface & RouteObserverBehaviorInterface,
+    // RouteObserverMixin calls currentRouteChanged() in
+    // connectedCallback(), so ensure other mixins/behaviors run their
+    // connectedCallback() first.
+    RouteObserverMixin(
+        FindShortcutMixin(CrContainerShadowMixin(PolymerElement))) as {
+      new (): PolymerElement & CrContainerShadowMixinInterface &
+          FindShortcutMixinInterface & RouteObserverMixinInterface,
     };
 
 class OsSettingsUiElement extends OsSettingsUiElementBase {
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_sandbox/privacy_sandbox_page.html b/chrome/browser/resources/settings/privacy_page/privacy_sandbox/privacy_sandbox_page.html
index 8e03670..4e53070 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_sandbox/privacy_sandbox_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_sandbox/privacy_sandbox_page.html
@@ -1 +1,23 @@
-Under construction.
+<style include="settings-shared"></style>
+
+<!-- TODO(b/254413936): Add image header. -->
+
+<!-- TODO(b/254414194): Add icons. -->
+<!-- TODO(crbug.com/1378703): Use string identifiers. -->
+<cr-link-row
+    id="privacySandboxTopicsLinkRow"
+    label="Mauris interdum lectus vitae lacinia"
+    sub-label="[[computePrivacySandboxTopicsSublabel_()]]"
+    on-click="onPrivacySandboxTopicsClick_"></cr-link-row>
+<cr-link-row
+    id="privacySandboxFledgeLinkRow"
+    class="hr"
+    label="Aenean erat leo"
+    sub-label="[[computePrivacySandboxFledgeSublabel_()]]"
+    on-click="onPrivacySandboxFledgeClick_"></cr-link-row>
+<cr-link-row
+    id="privacySandboxMeasurementLinkRow"
+    class="hr"
+    label="Vestibulum augue erat"
+    sub-label="[[computePrivacySandboxMeasurementSublabel_()]]"
+    on-click="onPrivacySandboxMeasurementClick_"></cr-link-row>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_sandbox/privacy_sandbox_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_sandbox/privacy_sandbox_page.ts
index c3812b30..690866b 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_sandbox/privacy_sandbox_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_sandbox/privacy_sandbox_page.ts
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
+import '../../settings_shared.css.js';
+
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getTemplate} from './privacy_sandbox_page.html.js';
@@ -14,6 +17,30 @@
   static get template() {
     return getTemplate();
   }
+
+  private computePrivacySandboxTopicsSublabel_(): string {
+    // TODO(b/254412639): Change sublabel based on the respective toggle being
+    // enabled.
+    return 'Enabled Nulla eros tortor, placerat blandit dictum a, interdum id metus';
+  }
+
+  private computePrivacySandboxFledgeSublabel_(): string {
+    // TODO(b/254410792): Change sublabel based on the respective toggle being
+    // enabled.
+    return 'Enabled Duis scelerisque a mi eget ultricies';
+  }
+
+  private computePrivacySandboxMeasurementSublabel_(): string {
+    // TODO(b/254412652): Change sublabel based on the respective toggle being
+    // enabled.
+    return 'Enabled Vivamus id lacus et lacus porttitor vulputate. Sed semper egestas orci vel maximus.';
+  }
+
+  private onPrivacySandboxTopicsClick_() {}
+
+  private onPrivacySandboxFledgeClick_() {}
+
+  private onPrivacySandboxMeasurementClick_() {}
 }
 
 declare global {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 2fa82233..fbb37a48 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3779,8 +3779,6 @@
       "cocoa/javascript_app_modal_dialog_cocoa.mm",
       "cocoa/key_equivalent_constants.h",
       "cocoa/key_equivalent_constants.mm",
-      "cocoa/keystone_infobar_delegate.h",
-      "cocoa/keystone_infobar_delegate.mm",
       "cocoa/l10n_util.h",
       "cocoa/l10n_util.mm",
       "cocoa/last_active_browser_cocoa.cc",
@@ -3867,6 +3865,13 @@
       "window_sizer/window_sizer_mac.mm",
     ]
 
+    if (enable_updater) {
+      sources += [
+        "cocoa/keystone_infobar_delegate.h",
+        "cocoa/keystone_infobar_delegate.mm",
+      ]
+    }
+
     allow_circular_includes_from += [ "//chrome/browser/apps/app_shim" ]
 
     deps += [
diff --git a/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc b/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
index 5fe8e82..4a7bd68 100644
--- a/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
+++ b/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
@@ -59,7 +59,6 @@
 #include "net/base/url_util.h"
 #include "storage/browser/file_system/file_system_context.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
-#include "ui/accessibility/accessibility_features.h"
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
@@ -90,7 +89,7 @@
      chromeos::settings::mojom::kSecurityAndSignInSubpagePathV2},
     {ChromePage::MAIN, ""},
     {ChromePage::MANAGEACCESSIBILITY,
-     chromeos::settings::mojom::kManageAccessibilitySubpagePath},
+     chromeos::settings::mojom::kAccessibilitySectionPath},
     {ChromePage::MANAGEACCESSIBILITYTTS,
      chromeos::settings::mojom::kTextToSpeechSubpagePath},
     {ChromePage::MULTIDEVICE,
@@ -428,10 +427,6 @@
   if (auto* it = kOSSettingsMap.find(page); it != kOSSettingsMap.end()) {
     Profile* profile = ProfileManager::GetActiveUserProfile();
     std::string sub_page = it->second;
-    if (features::IsAccessibilityOSSettingsVisibilityEnabled() &&
-        it->first == ChromePage::MANAGEACCESSIBILITY) {
-      sub_page = chromeos::settings::mojom::kAccessibilitySectionPath;
-    }
     chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(profile,
                                                                  sub_page);
     return;
diff --git a/chrome/browser/ui/ash/arc_open_url_delegate_impl_browsertest.cc b/chrome/browser/ui/ash/arc_open_url_delegate_impl_browsertest.cc
index d220199..e831849 100644
--- a/chrome/browser/ui/ash/arc_open_url_delegate_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/arc_open_url_delegate_impl_browsertest.cc
@@ -34,7 +34,6 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/accessibility/accessibility_features.h"
 #include "url/gurl.h"
 
 namespace {
@@ -57,31 +56,6 @@
 
 using ArcOpenUrlDelegateImplBrowserTest = InProcessBrowserTest;
 
-class ArcOpenUrlDelegateImplBrowserParamTest
-    : public ArcOpenUrlDelegateImplBrowserTest,
-      public testing::WithParamInterface<bool> {
- public:
-  ArcOpenUrlDelegateImplBrowserParamTest() = default;
-  ArcOpenUrlDelegateImplBrowserParamTest(
-      const ArcOpenUrlDelegateImplBrowserParamTest&) = delete;
-  ArcOpenUrlDelegateImplBrowserParamTest& operator=(
-      const ArcOpenUrlDelegateImplBrowserParamTest&) = delete;
-  ~ArcOpenUrlDelegateImplBrowserParamTest() override = default;
-
-  // ArcOpenUrlDelegateImplBrowserTest:
-  void SetUp() override {
-    scoped_feature_list_.InitWithFeatureState(
-        features::kAccessibilityOSSettingsVisibility,
-        IsAccessibilityOSSettingsVisibilityEnabled());
-    ArcOpenUrlDelegateImplBrowserTest::SetUp();
-  }
-
-  bool IsAccessibilityOSSettingsVisibilityEnabled() const { return GetParam(); }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
 using ArcOpenUrlDelegateImplWebAppBrowserTest =
     web_app::WebAppNavigationBrowserTest;
 
@@ -351,10 +325,7 @@
           chromeos::settings::mojom::kSecurityAndSignInSubpagePathV2));
   TestOpenOSSettingsChromePage(
       ChromePage::MANAGEACCESSIBILITY,
-      base_url.Resolve(
-          features::IsAccessibilityOSSettingsVisibilityEnabled()
-              ? chromeos::settings::mojom::kAccessibilitySectionPath
-              : chromeos::settings::mojom::kManageAccessibilitySubpagePath));
+      base_url.Resolve(chromeos::settings::mojom::kAccessibilitySectionPath));
   TestOpenOSSettingsChromePage(
       ChromePage::NETWORKSTYPEVPN,
       base_url.Resolve(chromeos::settings::mojom::kVpnDetailsSubpagePath));
@@ -408,13 +379,7 @@
   TestOpenChromePage(ChromePage::ABOUTBLANK, GURL(url::kAboutBlankURL));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    ArcOpenUrlDelegateImplBrowserParamTest,
-    /*IsAccessibilityOSSettingsVisibilityEnabled()=*/::testing::Bool());
-
-IN_PROC_BROWSER_TEST_P(ArcOpenUrlDelegateImplBrowserParamTest,
-                       TestOpenChromePage) {
+IN_PROC_BROWSER_TEST_F(ArcOpenUrlDelegateImplBrowserTest, TestOpenChromePage) {
   // Install the Settings App.
   ash::SystemWebAppManager::GetForTest(browser()->profile())
       ->InstallSystemAppsForTesting();
diff --git a/chrome/browser/ui/ash/login_screen_client_impl.cc b/chrome/browser/ui/ash/login_screen_client_impl.cc
index 9a6d21ea..0e951ae 100644
--- a/chrome/browser/ui/ash/login_screen_client_impl.cc
+++ b/chrome/browser/ui/ash/login_screen_client_impl.cc
@@ -154,7 +154,7 @@
     const AccountId& account_id,
     const std::string& access_code,
     base::Time validation_time) {
-  return chromeos::parent_access::ParentAccessService::Get()
+  return ash::parent_access::ParentAccessService::Get()
       .ValidateParentAccessCode(account_id, access_code, validation_time);
 }
 
@@ -220,7 +220,7 @@
   auto supervised_action = prefilled_account.empty()
                                ? SupervisedAction::kAddUser
                                : SupervisedAction::kReauth;
-  if (chromeos::parent_access::ParentAccessService::Get().IsApprovalRequired(
+  if (ash::parent_access::ParentAccessService::Get().IsApprovalRequired(
           supervised_action)) {
     // Show the client native parent access widget and processed to GAIA signin
     // flow in |OnParentAccessValidation| when validation success.
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
index 12de7b2..8313869 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
@@ -121,6 +121,7 @@
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/app_window/native_app_window.h"
+#include "extensions/browser/browsertest_util.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry_factory.h"
 #include "extensions/browser/extension_system.h"
@@ -195,6 +196,17 @@
       .id();
 }
 
+void ExecuteScriptInChromeVox(Browser* browser, const std::string& script) {
+  std::string execute_script = R"JS((async function() {
+      )JS" + script + R"JS(
+      window.domAutomationController.send('done');
+  })())JS";
+
+  extensions::browsertest_util::ExecuteScriptInBackgroundPage(
+      browser->profile(), extension_misc::kChromeVoxExtensionId,
+      execute_script);
+}
+
 void ExtendHotseat(Browser* browser) {
   ash::RootWindowController* const controller =
       ash::Shell::GetRootWindowControllerWithDisplayId(
@@ -2787,12 +2799,11 @@
   speech_monitor.ExpectSpeechPattern("*");
   speech_monitor.Call([this]() {
     // Disable earcons (https://crbug.com/396507).
-    const std::string script("ChromeVox.earcons.playEarcon = function() {};");
-    extensions::ExtensionHost* host =
-        extensions::ProcessManager::Get(browser()->profile())
-            ->GetBackgroundHostForExtension(
-                extension_misc::kChromeVoxExtensionId);
-    content::ExecuteScriptAsync(host->host_contents(), script);
+    const std::string script(R"JS(
+        const module = await import('/chromevox/background/chromevox.js');
+        module.ChromeVox.earcons.playEarcon = function() {};
+    )JS");
+    ExecuteScriptInChromeVox(browser(), script);
   });
 
   // Wait for an utterance from the browser before the test starts traversal
diff --git a/chrome/browser/ui/ash/system_tray_client_impl.cc b/chrome/browser/ui/ash/system_tray_client_impl.cc
index e7dc8b2..dfe30b1 100644
--- a/chrome/browser/ui/ash/system_tray_client_impl.cc
+++ b/chrome/browser/ui/ash/system_tray_client_impl.cc
@@ -74,7 +74,6 @@
 #include "components/session_manager/core/session_manager_observer.h"
 #include "components/user_manager/user_manager.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
-#include "ui/accessibility/accessibility_features.h"
 #include "ui/events/event_constants.h"
 #include "url/gurl.h"
 using session_manager::SessionManager;
@@ -508,14 +507,10 @@
   // mode, so users can't get to other OS Settings (such as Wi-Fi, Date / Time).
   // We plan to remove this after we add a standalone OS Accessibility page for
   // kiosk mode, which blocks access to other OS settings.
-  bool is_kiosk = user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp();
-  if (!is_kiosk && ::features::IsAccessibilityOSSettingsVisibilityEnabled()) {
-    ShowSettingsSubPageForActiveUser(
-        chromeos::settings::mojom::kAccessibilitySectionPath);
-  } else {
-    ShowSettingsSubPageForActiveUser(
-        chromeos::settings::mojom::kManageAccessibilitySubpagePath);
-  }
+  ShowSettingsSubPageForActiveUser(
+      user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp()
+          ? chromeos::settings::mojom::kManageAccessibilitySubpagePath
+          : chromeos::settings::mojom::kAccessibilitySectionPath);
 }
 
 void SystemTrayClientImpl::ShowGestureEducationHelp() {
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 7cbabbcd..ccfa84f 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1285,6 +1285,14 @@
   return window_->DoBrowserControlsShrinkRendererSize(contents);
 }
 
+int Browser::GetVirtualKeyboardHeight(content::WebContents* contents) {
+  // This API is currently only used by View Transitions when the virtual
+  // keyboard resizes content.  On desktop platforms, the virtual keyboard can
+  // only inset the visual viewport so it shouldn't ever be called.
+  NOTIMPLEMENTED();
+  return 0;
+}
+
 void Browser::SetTopControlsGestureScrollInProgress(bool in_progress) {
   window_->SetTopControlsGestureScrollInProgress(in_progress);
 }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 201e468d..b50337f 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -660,6 +660,7 @@
   int GetTopControlsHeight() override;
   bool DoBrowserControlsShrinkRendererSize(
       content::WebContents* contents) override;
+  int GetVirtualKeyboardHeight(content::WebContents* contents) override;
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   bool CanOverscrollContent() override;
   bool ShouldPreserveAbortedURLs(content::WebContents* source) override;
diff --git a/chrome/browser/ui/omnibox/omnibox_pedal_implementations.cc b/chrome/browser/ui/omnibox/omnibox_pedal_implementations.cc
index b6f03806..50f0b61 100644
--- a/chrome/browser/ui/omnibox/omnibox_pedal_implementations.cc
+++ b/chrome/browser/ui/omnibox/omnibox_pedal_implementations.cc
@@ -27,10 +27,6 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ui/accessibility/accessibility_features.h"
-#endif
-
 // =============================================================================
 
 class OmniboxPedalClearBrowsingData : public OmniboxPedal {
@@ -1710,16 +1706,7 @@
                 IDS_OMNIBOX_PEDAL_MANAGE_CHROMEOS_ACCESSIBILITY_SUGGESTION_CONTENTS,
                 IDS_ACC_OMNIBOX_PEDAL_MANAGE_CHROMEOS_ACCESSIBILITY_SUFFIX,
                 IDS_ACC_OMNIBOX_PEDAL_MANAGE_CHROMEOS_ACCESSIBILITY),
-            GURL("chrome://os-settings/manageAccessibility")) {}
-
-  void OnLoaded() override {
-    OmniboxPedal::OnLoaded();
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    if (::features::IsAccessibilityOSSettingsVisibilityEnabled()) {
-      SetNavigationUrl(GURL("chrome://os-settings/osAccessibility"));
-    }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-  }
+            GURL("chrome://os-settings/osAccessibility")) {}
 
   std::vector<SynonymGroupSpec> SpecifySynonymGroups(
       bool locale_is_english) const override {
diff --git a/chrome/browser/ui/read_later/reading_list_model_factory.cc b/chrome/browser/ui/read_later/reading_list_model_factory.cc
index bbe827d..64a1a73 100644
--- a/chrome/browser/ui/read_later/reading_list_model_factory.cc
+++ b/chrome/browser/ui/read_later/reading_list_model_factory.cc
@@ -22,7 +22,7 @@
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/reading_list/core/reading_list_model_impl.h"
 #include "components/reading_list/core/reading_list_pref_names.h"
-#include "components/reading_list/core/reading_list_store.h"
+#include "components/reading_list/core/reading_list_sync_bridge.h"
 #include "components/sync/base/report_unrecoverable_error.h"
 #include "components/sync/model/client_tag_based_model_type_processor.h"
 #include "components/sync/model/model_type_store_service.h"
@@ -41,11 +41,12 @@
           syncer::READING_LIST,
           base::BindRepeating(&syncer::ReportUnrecoverableError,
                               chrome::GetChannel()));
-  std::unique_ptr<ReadingListStore> store = std::make_unique<ReadingListStore>(
+  auto bridge = std::make_unique<ReadingListSyncBridge>(
       std::move(store_factory), std::move(change_processor));
 
   return std::make_unique<ReadingListModelImpl>(
-      std::move(store), profile->GetPrefs(), base::DefaultClock::GetInstance());
+      std::move(bridge), profile->GetPrefs(),
+      base::DefaultClock::GetInstance());
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 8cae23d..6d143c95 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -73,8 +73,10 @@
 
 #if BUILDFLAG(IS_MAC)
 #include "base/mac/mac_util.h"
+#if BUILDFLAG(ENABLE_UPDATER)
 #include "chrome/browser/ui/cocoa/keystone_infobar_delegate.h"
 #endif
+#endif  // BUILDFLAG(IS_MAC)
 
 #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/win/conflicts/incompatible_applications_updater.h"
@@ -204,7 +206,7 @@
 
   web_app::MaybeInstallAppFromCommandLine(*command_line_, *profile);
 
-#if BUILDFLAG(IS_MAC)
+#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER)
   if (process_startup == chrome::startup::IsProcessStartup::kYes) {
     // Check whether the auto-update system needs to be promoted from user
     // to system.
diff --git a/chrome/browser/ui/views/bubble_anchor_util_views.cc b/chrome/browser/ui/views/bubble_anchor_util_views.cc
index f65939f..84a4399 100644
--- a/chrome/browser/ui/views/bubble_anchor_util_views.cc
+++ b/chrome/browser/ui/views/bubble_anchor_util_views.cc
@@ -38,15 +38,12 @@
             browser_view->GetLocationBarView()->location_icon_view(),
             views::BubbleBorder::TOP_LEFT};
 
-// TODO(https://crbug.com/1346734): Enable this on all platforms.
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   if (anchor == kLocationBar && browser_view->GetIsPictureInPictureType()) {
     auto* frame_view = static_cast<PictureInPictureBrowserFrameView*>(
         browser_view->frame()->GetFrameView());
     return {frame_view->GetLocationIconView(),
             frame_view->GetLocationIconView(), views::BubbleBorder::TOP_LEFT};
   }
-#endif
 
   if (anchor == kCustomTabBar && browser_view->toolbar()->custom_tab_bar())
     return {browser_view->toolbar()->custom_tab_bar(),
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
index 4543b32..95bfe52 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
@@ -72,11 +72,10 @@
 std::unique_ptr<BrowserNonClientFrameView> CreateBrowserNonClientFrameView(
     BrowserFrame* frame,
     BrowserView* browser_view) {
-// TODO(https://crbug.com/1346734): Enable it on all platforms.
-#if BUILDFLAG(IS_LINUX)
   if (browser_view->browser()->is_type_picture_in_picture()) {
     auto view =
         std::make_unique<PictureInPictureBrowserFrameView>(frame, browser_view);
+#if BUILDFLAG(IS_LINUX)
     auto* profile = browser_view->browser()->profile();
     auto* linux_ui_theme = ui::LinuxUiTheme::GetForProfile(profile);
     auto* theme_service_factory = ThemeServiceFactory::GetForProfile(profile);
@@ -87,9 +86,9 @@
       view->SetWindowFrameProvider(
           linux_ui_theme->GetWindowFrameProvider(solid_frame));
     }
+#endif  // BUILDFLAG(IS_LINUX)
     return view;
   }
-#endif
 
 #if BUILDFLAG(IS_WIN)
   if (frame->ShouldUseNativeFrame())
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_dialog_browsertest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_dialog_browsertest.cc
index 5d1cff62..4ec23501 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_dialog_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/feature_list.h"
 #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h"
 
 #include "build/build_config.h"
@@ -478,6 +479,9 @@
     description->mutable_source()->set_url("https://example.com");
     description->mutable_source()->set_label("Example source");
 
+    auto* more_about = site_info->mutable_more_about();
+    more_about->set_url("https://example.com/moreinfo");
+
     optimization_metadata.SetAnyMetadataForTesting(metadata);
 
     auto* optimization_guide_decider =
@@ -545,6 +549,9 @@
 
 IN_PROC_BROWSER_TEST_F(PageInfoBubbleViewAboutThisSiteDialogBrowserTest,
                        InvokeUi_AboutThisSiteSubpage) {
+  // The subpage only exists in the old UI.
+  if (base::FeatureList::IsEnabled(page_info::kPageInfoAboutThisSiteMoreInfo))
+    return;
   ShowAndVerifyUi();
 }
 
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index c785725..16c561df 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -377,7 +377,7 @@
   model_->MoveGroupTo(group, final_index);
 }
 
-bool BrowserTabStripController::ToggleTabGroupCollapsedState(
+void BrowserTabStripController::ToggleTabGroupCollapsedState(
     const tab_groups::TabGroupId group,
     ToggleTabGroupCollapsedStateOrigin origin) {
   const bool is_currently_collapsed = IsGroupCollapsed(group);
@@ -390,18 +390,19 @@
     if (model_->GetTabGroupForTab(GetActiveIndex()) == group) {
       // If the active tab is in the group that is toggling to collapse, the
       // active tab should switch to the next available tab. If there are no
-      // available tabs for the active tab to switch to, the group will not
-      // toggle to collapse.
+      // available tabs for the active tab to switch to, a new tab will
+      // be created.
       const absl::optional<int> next_active =
           model_->GetNextExpandedActiveTab(GetActiveIndex(), group);
-      if (!next_active.has_value()) {
-        base::RecordAction(base::UserMetricsAction("TabGroups_CannotCollapse"));
-        return false;
+      if (next_active.has_value()) {
+        model_->ActivateTabAt(
+            next_active.value(),
+            TabStripUserGestureDetails(
+                TabStripUserGestureDetails::GestureType::kOther));
+      } else {
+        // Create a new tab that will automatically be activated
+        CreateNewTab();
       }
-      model_->ActivateTabAt(
-          next_active.value(),
-          TabStripUserGestureDetails(
-              TabStripUserGestureDetails::GestureType::kOther));
     } else {
       // If the active tab is not in the group that is toggling to collapse,
       // reactive the active tab to deselect any other potentially selected
@@ -421,7 +422,6 @@
   tab_groups::TabGroupVisualData new_data(
       GetGroupTitle(group), GetGroupColorId(group), !is_currently_collapsed);
   model_->group_model()->GetTabGroup(group)->SetVisualData(new_data, true);
-  return true;
 }
 
 void BrowserTabStripController::ShowContextMenuForTab(
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
index bad1841b..a1c11d2 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
@@ -78,7 +78,7 @@
   void RemoveTabFromGroup(int model_index) override;
   void MoveTab(int start_index, int final_index) override;
   void MoveGroup(const tab_groups::TabGroupId& group, int final_index) override;
-  bool ToggleTabGroupCollapsedState(
+  void ToggleTabGroupCollapsedState(
       const tab_groups::TabGroupId group,
       ToggleTabGroupCollapsedStateOrigin origin) override;
   void ShowContextMenuForTab(Tab* tab,
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
index 88df1bf7..6cde3c7 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
@@ -51,13 +51,12 @@
 void FakeBaseTabStripController::MoveGroup(const tab_groups::TabGroupId& group,
                                            int to_index) {}
 
-bool FakeBaseTabStripController::ToggleTabGroupCollapsedState(
+void FakeBaseTabStripController::ToggleTabGroupCollapsedState(
     const tab_groups::TabGroupId group,
     ToggleTabGroupCollapsedStateOrigin origin) {
   fake_group_data_ = tab_groups::TabGroupVisualData(
       fake_group_data_.title(), fake_group_data_.color(),
       !fake_group_data_.is_collapsed());
-  return true;
 }
 
 void FakeBaseTabStripController::RemoveTab(int index) {
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
index 8bcc09a..116c03f 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
@@ -54,7 +54,7 @@
   void ToggleTabAudioMute(int index) override;
   void MoveTab(int from_index, int to_index) override;
   void MoveGroup(const tab_groups::TabGroupId&, int to_index) override;
-  bool ToggleTabGroupCollapsedState(
+  void ToggleTabGroupCollapsedState(
       const tab_groups::TabGroupId group,
       ToggleTabGroupCollapsedStateOrigin origin) override;
   void ShowContextMenuForTab(Tab* tab,
diff --git a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
index 94d27ec..d1f5a96 100644
--- a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
@@ -19,11 +19,9 @@
   return tab_container_->GetTabAtModelIndex(index);
 }
 
-bool FakeTabSlotController::ToggleTabGroupCollapsedState(
+void FakeTabSlotController::ToggleTabGroupCollapsedState(
     const tab_groups::TabGroupId group,
-    ToggleTabGroupCollapsedStateOrigin origin) {
-  return false;
-}
+    ToggleTabGroupCollapsedStateOrigin origin) {}
 
 bool FakeTabSlotController::IsActiveTab(const Tab* tab) const {
   return active_tab_ == tab;
diff --git a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
index ebbae9b..25f1c66d 100644
--- a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
+++ b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
@@ -41,7 +41,7 @@
   void ShiftTabPrevious(Tab* tab) override {}
   void MoveTabFirst(Tab* tab) override {}
   void MoveTabLast(Tab* tab) override {}
-  bool ToggleTabGroupCollapsedState(
+  void ToggleTabGroupCollapsedState(
       const tab_groups::TabGroupId group,
       ToggleTabGroupCollapsedStateOrigin origin =
           ToggleTabGroupCollapsedStateOrigin::kImplicitAction) override;
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
index 5820274..95ebd88 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view_browsertest.cc
@@ -205,8 +205,7 @@
   ASSERT_FALSE(browser_view->tabstrip()->tab_at(0)->HasFreezingVoteToken());
   ASSERT_FALSE(browser_view->tabstrip()->tab_at(1)->HasFreezingVoteToken());
   ASSERT_FALSE(browser_view->tabstrip()->tab_at(2)->HasFreezingVoteToken());
-  ASSERT_TRUE(
-      browser_view->tabstrip()->ToggleTabGroupCollapsedState(group.value()));
+  browser_view->tabstrip()->ToggleTabGroupCollapsedState(group.value());
   EXPECT_TRUE(browser_view->tabstrip()->tab_at(0)->HasFreezingVoteToken());
   EXPECT_TRUE(browser_view->tabstrip()->tab_at(1)->HasFreezingVoteToken());
   EXPECT_FALSE(browser_view->tabstrip()->tab_at(2)->HasFreezingVoteToken());
diff --git a/chrome/browser/ui/views/tabs/tab_group_header.cc b/chrome/browser/ui/views/tabs/tab_group_header.cc
index 39e338c..1376755 100644
--- a/chrome/browser/ui/views/tabs/tab_group_header.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_header.cc
@@ -130,15 +130,13 @@
   if ((event.key_code() == ui::VKEY_SPACE ||
        event.key_code() == ui::VKEY_RETURN) &&
       !editor_bubble_tracker_.is_open()) {
-    bool successful_toggle = tab_slot_controller_->ToggleTabGroupCollapsedState(
+    tab_slot_controller_->ToggleTabGroupCollapsedState(
         group().value(), ToggleTabGroupCollapsedStateOrigin::kKeyboard);
-    if (successful_toggle) {
 #if BUILDFLAG(IS_WIN)
-      NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
+    NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
 #else
-      NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
+    NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
 #endif
-    }
     return true;
   }
 
diff --git a/chrome/browser/ui/views/tabs/tab_slot_controller.h b/chrome/browser/ui/views/tabs/tab_slot_controller.h
index 6a43f96..f729425 100644
--- a/chrome/browser/ui/views/tabs/tab_slot_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_slot_controller.h
@@ -90,7 +90,7 @@
 
   // Switches the collapsed state of a tab group. Returns false if the state was
   // not successfully switched.
-  virtual bool ToggleTabGroupCollapsedState(
+  virtual void ToggleTabGroupCollapsedState(
       const tab_groups::TabGroupId group,
       ToggleTabGroupCollapsedStateOrigin origin =
           ToggleTabGroupCollapsedStateOrigin::kImplicitAction) = 0;
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 463fc76e..1979dc20d 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1535,10 +1535,21 @@
       l10n_util::GetStringUTF16(IDS_TAB_AX_ANNOUNCE_MOVED_LAST));
 }
 
-bool TabStrip::ToggleTabGroupCollapsedState(
+void TabStrip::ToggleTabGroupCollapsedState(
     const tab_groups::TabGroupId group,
     ToggleTabGroupCollapsedStateOrigin origin) {
-  return controller_->ToggleTabGroupCollapsedState(group, origin);
+  int tab_count = GetTabCount();
+  controller_->ToggleTabGroupCollapsedState(group, origin);
+  // If tab count changed, all tab groups are collapsed and we have
+  // created a new tab. We need to exit closing mode to resize the new
+  // tab immediately.
+  // TODO(crbug/1384151): This should be captured along with the
+  // ToggleTabGroup logic, so other callers to
+  // TabStripController::ToggleTabGroupCollapsedState see the same
+  // behavior.
+  if (tab_count != GetTabCount()) {
+    tab_container_->ExitTabClosingMode();
+  }
 }
 
 void TabStrip::NotifyTabGroupEditorBubbleOpened() {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index a257fd42..1d0b7e8 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -260,7 +260,7 @@
   void ShiftTabPrevious(Tab* tab) override;
   void MoveTabFirst(Tab* tab) override;
   void MoveTabLast(Tab* tab) override;
-  bool ToggleTabGroupCollapsedState(
+  void ToggleTabGroupCollapsedState(
       const tab_groups::TabGroupId group,
       ToggleTabGroupCollapsedStateOrigin origin =
           ToggleTabGroupCollapsedStateOrigin::kImplicitAction) override;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc b/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
index 7deaa79..e8213ea 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
@@ -848,15 +848,18 @@
   EXPECT_EQ(1, tab_strip()->GetActiveIndex());
 }
 
-IN_PROC_BROWSER_TEST_F(TabStripBrowsertest, CollapseGroup_Fails) {
+IN_PROC_BROWSER_TEST_F(TabStripBrowsertest, CollapseGroup_CreatesNewTab) {
+  ASSERT_EQ(1, tab_strip_model()->count());
   AppendTab();
+  ASSERT_EQ(2, tab_strip_model()->count());
 
   tab_groups::TabGroupId group = AddTabToNewGroup(0);
   tab_strip_model()->AddToExistingGroup({1}, group);
   ASSERT_FALSE(tab_strip()->IsGroupCollapsed(group));
   tab_strip()->ToggleTabGroupCollapsedState(group);
+  ASSERT_EQ(3, tab_strip_model()->count());
 
-  EXPECT_FALSE(tab_strip()->IsGroupCollapsed(group));
+  EXPECT_TRUE(tab_strip()->IsGroupCollapsed(group));
 }
 
 IN_PROC_BROWSER_TEST_F(TabStripBrowsertest,
diff --git a/chrome/browser/ui/views/tabs/tab_strip_controller.h b/chrome/browser/ui/views/tabs/tab_strip_controller.h
index 4b231b8..5daec72 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_strip_controller.h
@@ -106,7 +106,7 @@
 
   // Switches the collapsed state of a tab group. Returns false if the state was
   // not successfully switched.
-  virtual bool ToggleTabGroupCollapsedState(
+  virtual void ToggleTabGroupCollapsedState(
       const tab_groups::TabGroupId group,
       ToggleTabGroupCollapsedStateOrigin origin =
           ToggleTabGroupCollapsedStateOrigin::kImplicitAction) = 0;
diff --git a/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.cc b/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.cc
index 3617f31b..3e718e0 100644
--- a/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.cc
+++ b/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.cc
@@ -7,12 +7,16 @@
 #include <memory>
 #include <utility>
 
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/shell.h"
+#include "ash/wm/window_dimmer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/ash/parent_access/parent_access_ui.mojom.h"
 #include "chrome/browser/ui/webui/ash/system_web_dialog_delegate.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
+#include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
@@ -21,6 +25,7 @@
 
 constexpr int kDialogHeightDp = 526;
 constexpr int kDialogWidthDp = 600;
+constexpr float kDimmerOpacity = 0.7f;
 
 }  // namespace
 
@@ -42,7 +47,10 @@
   ParentAccessDialog* dialog =
       new ParentAccessDialog(std::move(params), std::move(callback));
 
+  // Dimmer should be shown before the dialog.
+  dialog->ShowDimmer();
   dialog->ShowSystemDialogForBrowserContext(profile);
+
   return ParentAccessDialogProvider::ShowError::kNone;
 }
 
@@ -111,6 +119,15 @@
       parent_access_params_(std::move(params)),
       callback_(std::move(callback)) {}
 
+void ParentAccessDialog::ShowDimmer() {
+  DCHECK_EQ(nullptr, dimmer_);
+  dimmer_ = std::make_unique<WindowDimmer>(
+      Shell::GetPrimaryRootWindow()->GetChildById(
+          kShellWindowId_SystemModalContainer));
+  dimmer_->SetDimOpacity(kDimmerOpacity);
+  dimmer_->window()->Show();
+}
+
 ParentAccessDialog::~ParentAccessDialog() {
   std::move(callback_).Run(
       result_ ? std::move(result_)
diff --git a/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.h b/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.h
index 05489d2..cbeaec3 100644
--- a/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.h
+++ b/chrome/browser/ui/webui/ash/parent_access/parent_access_dialog.h
@@ -16,6 +16,8 @@
 
 namespace ash {
 
+class WindowDimmer;
+
 // Dialog which embeds the Parent Access UI, which verifies a
 // parent during a child session.
 class ParentAccessDialog : public ParentAccessUIHandlerDelegate,
@@ -67,6 +69,9 @@
       parent_access_ui::mojom::ParentAccessParamsPtr params,
       Callback callback);
 
+  // Creates and shows additional dimmer underneath the dialog.
+  void ShowDimmer();
+
  protected:
   ~ParentAccessDialog() override;
 
@@ -76,6 +81,10 @@
   parent_access_ui::mojom::ParentAccessParamsPtr parent_access_params_;
   Callback callback_;
 
+  // The dimmer shown underneath the dialog in order to mitigate spoofing by the
+  // malicious website. The dimmer clearly renders over the browser UI.
+  std::unique_ptr<WindowDimmer> dimmer_;
+
   // The Parent Access Dialog result passed back to the caller when the dialog
   // completes.
   std::unique_ptr<Result> result_;
diff --git a/chrome/browser/ui/webui/settings/ash/accessibility_section.cc b/chrome/browser/ui/webui/settings/ash/accessibility_section.cc
index 85d11aa..187396e 100644
--- a/chrome/browser/ui/webui/settings/ash/accessibility_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/accessibility_section.cc
@@ -74,18 +74,58 @@
        {.setting = mojom::Setting::kA11yQuickSettings},
        {IDS_OS_SETTINGS_TAG_A11Y_ALWAYS_SHOW_OPTIONS_ALT1,
         SearchConcept::kAltTagEnd}},
+      {IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE,
+       mojom::kTextToSpeechPagePath,
+       mojom::SearchResultIcon::kA11y,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSubpage,
+       {.subpage = mojom::Subpage::kTextToSpeechPage},
+       {IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE_ALT1,
+        IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE_ALT2,
+        IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE_ALT3,
+        IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE_ALT4,
+        SearchConcept::kAltTagEnd}},
+      {IDS_OS_SETTINGS_TAG_A11Y_DISPLAY_AND_MAGNIFICATION_PAGE,
+       mojom::kDisplayAndMagnificationSubpagePath,
+       mojom::SearchResultIcon::kA11y,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSubpage,
+       {.subpage = mojom::Subpage::kDisplayAndMagnification},
+       {IDS_OS_SETTINGS_TAG_A11Y_DISPLAY_AND_MAGNIFICATION_PAGE_ALT1,
+        SearchConcept::kAltTagEnd}},
+      {IDS_OS_SETTINGS_TAG_A11Y_KEYBOARD_AND_TEXT_INPUT_PAGE,
+       mojom::kKeyboardAndTextInputSubpagePath,
+       mojom::SearchResultIcon::kA11y,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSubpage,
+       {.subpage = mojom::Subpage::kKeyboardAndTextInput}},
+      {IDS_OS_SETTINGS_TAG_A11Y_CURSOR_AND_TOUCHPAD_PAGE,
+       mojom::kCursorAndTouchpadSubpagePath,
+       mojom::SearchResultIcon::kA11y,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSubpage,
+       {.subpage = mojom::Subpage::kCursorAndTouchpad},
+       {IDS_OS_SETTINGS_TAG_A11Y_CURSOR_AND_TOUCHPAD_PAGE_ALT1,
+        IDS_OS_SETTINGS_TAG_A11Y_CURSOR_AND_TOUCHPAD_PAGE_ALT2,
+        SearchConcept::kAltTagEnd}},
+      {IDS_OS_SETTINGS_TAG_A11Y_AUDIO_AND_CAPTIONS_PAGE,
+       mojom::kAudioAndCaptionsSubpagePath,
+       mojom::SearchResultIcon::kA11y,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSubpage,
+       {.subpage = mojom::Subpage::kAudioAndCaptions},
+       {IDS_OS_SETTINGS_TAG_A11Y_AUDIO_AND_CAPTIONS_PAGE_ALT1,
+        IDS_OS_SETTINGS_TAG_A11Y_AUDIO_AND_CAPTIONS_PAGE_ALT2,
+        IDS_OS_SETTINGS_TAG_A11Y_AUDIO_AND_CAPTIONS_PAGE_ALT3,
+        SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_STICKY_KEYS,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kKeyboardAndTextInputSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kKeyboardAndTextInputSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
        {.setting = mojom::Setting::kStickyKeys}},
       {IDS_OS_SETTINGS_TAG_A11Y_LARGE_CURSOR,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kCursorAndTouchpadSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kCursorAndTouchpadSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -103,9 +143,7 @@
        {IDS_OS_SETTINGS_TAG_A11Y_ALT1, IDS_OS_SETTINGS_TAG_A11Y_ALT2,
         SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_DOCKED_MAGNIFIER,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kDisplayAndMagnificationSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kDisplayAndMagnificationSubpagePath,
        mojom::SearchResultIcon::kDockedMagnifier,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -113,9 +151,7 @@
        {IDS_OS_SETTINGS_TAG_A11Y_DOCKED_MAGNIFIER_ALT1,
         SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11y_CHROMEVOX,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kTextToSpeechPagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kTextToSpeechPagePath,
        mojom::SearchResultIcon::kChromeVox,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -123,9 +159,7 @@
        {IDS_OS_SETTINGS_TAG_A11y_CHROMEVOX_ALT1,
         IDS_OS_SETTINGS_TAG_A11y_CHROMEVOX_ALT2, SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_MONO_AUDIO,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kAudioAndCaptionsSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kAudioAndCaptionsSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kLow,
        mojom::SearchResultType::kSetting,
@@ -148,9 +182,7 @@
        mojom::SearchResultType::kSubpage,
        {.subpage = mojom::Subpage::kCaptions}},
       {IDS_OS_SETTINGS_TAG_A11Y_HIGHLIGHT_CURSOR,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kCursorAndTouchpadSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kCursorAndTouchpadSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -167,17 +199,13 @@
        {.subpage = mojom::Subpage::kManageAccessibility},
        {IDS_OS_SETTINGS_TAG_A11Y_MANAGE_ALT1, SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_ON_SCREEN_KEYBOARD,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kKeyboardAndTextInputSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kKeyboardAndTextInputSubpagePath,
        mojom::SearchResultIcon::kOnScreenKeyboard,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
        {.setting = mojom::Setting::kOnScreenKeyboard}},
       {IDS_OS_SETTINGS_TAG_A11Y_HIGHLIGHT_TEXT_CARET,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kKeyboardAndTextInputSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kKeyboardAndTextInputSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -185,9 +213,7 @@
        {IDS_OS_SETTINGS_TAG_A11Y_HIGHLIGHT_TEXT_CARET_ALT1,
         SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_DICTATION,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kKeyboardAndTextInputSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kKeyboardAndTextInputSubpagePath,
        mojom::SearchResultIcon::kDictation,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -197,9 +223,7 @@
         IDS_OS_SETTINGS_TAG_A11Y_DICTATION_ALT3,
         IDS_OS_SETTINGS_TAG_A11Y_DICTATION_ALT4, SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_HIGH_CONTRAST,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kDisplayAndMagnificationSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kDisplayAndMagnificationSubpagePath,
        mojom::SearchResultIcon::kContrast,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -207,9 +231,7 @@
        {IDS_OS_SETTINGS_TAG_A11Y_HIGH_CONTRAST_ALT1,
         SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_HIGHLIGHT_KEYBOARD_FOCUS,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kKeyboardAndTextInputSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kKeyboardAndTextInputSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -217,9 +239,7 @@
        {IDS_OS_SETTINGS_TAG_A11Y_HIGHLIGHT_KEYBOARD_FOCUS_ALT1,
         SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_STARTUP_SOUND,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kAudioAndCaptionsSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kAudioAndCaptionsSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -227,9 +247,7 @@
        {IDS_OS_SETTINGS_TAG_A11Y_STARTUP_SOUND_ALT1,
         SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_AUTOMATICALLY_CLICK,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kCursorAndTouchpadSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kCursorAndTouchpadSubpagePath,
        mojom::SearchResultIcon::kAutoclick,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -237,9 +255,7 @@
        {IDS_OS_SETTINGS_TAG_A11Y_AUTOMATICALLY_CLICK_ALT1,
         SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_SELECT_TO_SPEAK,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kTextToSpeechPagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kTextToSpeechPagePath,
        mojom::SearchResultIcon::kSelectToSpeak,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -264,9 +280,7 @@
        mojom::SearchResultType::kSetting,
        {.setting = mojom::Setting::kTextToSpeechVolume}},
       {IDS_OS_SETTINGS_TAG_A11Y_FULLSCREEN_MAGNIFIER,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kDisplayAndMagnificationSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kDisplayAndMagnificationSubpagePath,
        mojom::SearchResultIcon::kFullscreenMagnifier,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -275,17 +289,13 @@
         IDS_OS_SETTINGS_TAG_A11Y_FULLSCREEN_MAGNIFIER_ALT2,
         SearchConcept::kAltTagEnd}},
       {IDS_OS_SETTINGS_TAG_A11Y_ENABLE_SWITCH_ACCESS,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kKeyboardAndTextInputSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kKeyboardAndTextInputSubpagePath,
        mojom::SearchResultIcon::kSwitchAccess,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
        {.setting = mojom::Setting::kEnableSwitchAccess}},
       {IDS_OS_SETTINGS_TAG_A11Y_CURSOR_COLOR,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kCursorAndTouchpadSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kCursorAndTouchpadSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -324,9 +334,7 @@
 GetA11yTabletNavigationButtonSearchConcepts() {
   static const base::NoDestructor<std::vector<SearchConcept>> tags({
       {IDS_OS_SETTINGS_TAG_A11Y_TABLET_NAVIGATION_BUTTONS,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kCursorAndTouchpadSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kCursorAndTouchpadSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -400,9 +408,7 @@
 GetA11yFullscreenMagnifierFocusFollowingSearchConcepts() {
   static const base::NoDestructor<std::vector<SearchConcept>> tags({
       {IDS_OS_SETTINGS_TAG_A11Y_FULLSCREEN_MAGNIFIER_FOCUS_FOLLOWING,
-       ::features::IsAccessibilityOSSettingsVisibilityEnabled()
-           ? mojom::kDisplayAndMagnificationSubpagePath
-           : mojom::kManageAccessibilitySubpagePath,
+       mojom::kDisplayAndMagnificationSubpagePath,
        mojom::SearchResultIcon::kA11y,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::SearchResultType::kSetting,
@@ -411,64 +417,10 @@
   return *tags;
 }
 
-const std::vector<SearchConcept>& GetA11yVisibilitySearchConcepts() {
-  static const base::NoDestructor<std::vector<SearchConcept>> tags({
-      {IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE,
-       mojom::kTextToSpeechPagePath,
-       mojom::SearchResultIcon::kA11y,
-       mojom::SearchResultDefaultRank::kMedium,
-       mojom::SearchResultType::kSubpage,
-       {.subpage = mojom::Subpage::kTextToSpeechPage},
-       {IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE_ALT1,
-        IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE_ALT2,
-        IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE_ALT3,
-        IDS_OS_SETTINGS_TAG_A11Y_TEXT_TO_SPEECH_PAGE_ALT4,
-        SearchConcept::kAltTagEnd}},
-      {IDS_OS_SETTINGS_TAG_A11Y_DISPLAY_AND_MAGNIFICATION_PAGE,
-       mojom::kDisplayAndMagnificationSubpagePath,
-       mojom::SearchResultIcon::kA11y,
-       mojom::SearchResultDefaultRank::kMedium,
-       mojom::SearchResultType::kSubpage,
-       {.subpage = mojom::Subpage::kDisplayAndMagnification},
-       {IDS_OS_SETTINGS_TAG_A11Y_DISPLAY_AND_MAGNIFICATION_PAGE_ALT1,
-        SearchConcept::kAltTagEnd}},
-      {IDS_OS_SETTINGS_TAG_A11Y_KEYBOARD_AND_TEXT_INPUT_PAGE,
-       mojom::kKeyboardAndTextInputSubpagePath,
-       mojom::SearchResultIcon::kA11y,
-       mojom::SearchResultDefaultRank::kMedium,
-       mojom::SearchResultType::kSubpage,
-       {.subpage = mojom::Subpage::kKeyboardAndTextInput}},
-      {IDS_OS_SETTINGS_TAG_A11Y_CURSOR_AND_TOUCHPAD_PAGE,
-       mojom::kCursorAndTouchpadSubpagePath,
-       mojom::SearchResultIcon::kA11y,
-       mojom::SearchResultDefaultRank::kMedium,
-       mojom::SearchResultType::kSubpage,
-       {.subpage = mojom::Subpage::kCursorAndTouchpad},
-       {IDS_OS_SETTINGS_TAG_A11Y_CURSOR_AND_TOUCHPAD_PAGE_ALT1,
-        IDS_OS_SETTINGS_TAG_A11Y_CURSOR_AND_TOUCHPAD_PAGE_ALT2,
-        SearchConcept::kAltTagEnd}},
-      {IDS_OS_SETTINGS_TAG_A11Y_AUDIO_AND_CAPTIONS_PAGE,
-       mojom::kAudioAndCaptionsSubpagePath,
-       mojom::SearchResultIcon::kA11y,
-       mojom::SearchResultDefaultRank::kMedium,
-       mojom::SearchResultType::kSubpage,
-       {.subpage = mojom::Subpage::kAudioAndCaptions},
-       {IDS_OS_SETTINGS_TAG_A11Y_AUDIO_AND_CAPTIONS_PAGE_ALT1,
-        IDS_OS_SETTINGS_TAG_A11Y_AUDIO_AND_CAPTIONS_PAGE_ALT2,
-        IDS_OS_SETTINGS_TAG_A11Y_AUDIO_AND_CAPTIONS_PAGE_ALT3,
-        SearchConcept::kAltTagEnd}},
-  });
-  return *tags;
-}
-
 bool IsLiveCaptionEnabled() {
   return captions::IsLiveCaptionFeatureSupported();
 }
 
-bool IsAccessibilityOSSettingsVisibilityEnabled() {
-  return ::features::IsAccessibilityOSSettingsVisibilityEnabled();
-}
-
 bool IsAccessibilitySelectToSpeakPageMigrationEnabled() {
   return ::features::IsAccessibilitySelectToSpeakPageMigrationEnabled();
 }
@@ -955,9 +907,6 @@
   html_source->AddString("tabletModeShelfNavigationButtonsLearnMoreUrl",
                          chrome::kTabletModeGesturesLearnMoreURL);
 
-  html_source->AddBoolean("isAccessibilityOSSettingsVisibilityEnabled",
-                          IsAccessibilityOSSettingsVisibilityEnabled());
-
   html_source->AddBoolean("isAccessibilitySelectToSpeakPageMigrationEnabled",
                           IsAccessibilitySelectToSpeakPageMigrationEnabled());
 
@@ -1031,52 +980,50 @@
       mojom::SearchResultDefaultRank::kMedium,
       mojom::kManageAccessibilitySubpagePath);
 
-  if (IsAccessibilityOSSettingsVisibilityEnabled()) {
-    // Text-to-Speech page.
+  // Text-to-Speech page.
+  generator->RegisterTopLevelSubpage(
+      IDS_SETTINGS_ACCESSIBILITY_TEXT_TO_SPEECH_LINK_TITLE,
+      mojom::Subpage::kTextToSpeechPage, mojom::SearchResultIcon::kA11y,
+      mojom::SearchResultDefaultRank::kMedium, mojom::kTextToSpeechPagePath);
+  // Select to speak options page.
+  if (IsAccessibilitySelectToSpeakPageMigrationEnabled()) {
     generator->RegisterTopLevelSubpage(
-        IDS_SETTINGS_ACCESSIBILITY_TEXT_TO_SPEECH_LINK_TITLE,
-        mojom::Subpage::kTextToSpeechPage, mojom::SearchResultIcon::kA11y,
-        mojom::SearchResultDefaultRank::kMedium, mojom::kTextToSpeechPagePath);
-    // Select to speak options page.
-    if (IsAccessibilitySelectToSpeakPageMigrationEnabled()) {
-      generator->RegisterTopLevelSubpage(
-          IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_LINK_TITLE,
-          mojom::Subpage::kSelectToSpeak, mojom::SearchResultIcon::kA11y,
-          mojom::SearchResultDefaultRank::kMedium,
-          mojom::kSelectToSpeakSubpagePath);
-      static constexpr mojom::Setting kSelectToSpeakSettings[] = {
-          mojom::Setting::kSelectToSpeakWordHighlight,
-          mojom::Setting::kSelectToSpeakBackgroundShading,
-          mojom::Setting::kSelectToSpeakNavigationControls,
-      };
-      RegisterNestedSettingBulk(mojom::Subpage::kSelectToSpeak,
-                                kSelectToSpeakSettings, generator);
-    }
-    // Display and magnification page.
-    generator->RegisterTopLevelSubpage(
-        IDS_SETTINGS_ACCESSIBILITY_DISPLAY_AND_MAGNIFICATION_LINK_TITLE,
-        mojom::Subpage::kDisplayAndMagnification,
-        mojom::SearchResultIcon::kA11y, mojom::SearchResultDefaultRank::kMedium,
-        mojom::kDisplayAndMagnificationSubpagePath);
-    // Keyboard and text input page.
-    generator->RegisterTopLevelSubpage(
-        IDS_SETTINGS_ACCESSIBILITY_KEYBOARD_AND_TEXT_INPUT_LINK_TITLE,
-        mojom::Subpage::kKeyboardAndTextInput, mojom::SearchResultIcon::kA11y,
+        IDS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_LINK_TITLE,
+        mojom::Subpage::kSelectToSpeak, mojom::SearchResultIcon::kA11y,
         mojom::SearchResultDefaultRank::kMedium,
-        mojom::kKeyboardAndTextInputSubpagePath);
-    // Cursor and touchpad page.
-    generator->RegisterTopLevelSubpage(
-        IDS_SETTINGS_ACCESSIBILITY_CURSOR_AND_TOUCHPAD_LINK_TITLE,
-        mojom::Subpage::kCursorAndTouchpad, mojom::SearchResultIcon::kA11y,
-        mojom::SearchResultDefaultRank::kMedium,
-        mojom::kCursorAndTouchpadSubpagePath);
-    // Audio and captions page.
-    generator->RegisterTopLevelSubpage(
-        IDS_SETTINGS_ACCESSIBILITY_AUDIO_AND_CAPTIONS_LINK_TITLE,
-        mojom::Subpage::kAudioAndCaptions, mojom::SearchResultIcon::kA11y,
-        mojom::SearchResultDefaultRank::kMedium,
-        mojom::kAudioAndCaptionsSubpagePath);
+        mojom::kSelectToSpeakSubpagePath);
+    static constexpr mojom::Setting kSelectToSpeakSettings[] = {
+        mojom::Setting::kSelectToSpeakWordHighlight,
+        mojom::Setting::kSelectToSpeakBackgroundShading,
+        mojom::Setting::kSelectToSpeakNavigationControls,
+    };
+    RegisterNestedSettingBulk(mojom::Subpage::kSelectToSpeak,
+                              kSelectToSpeakSettings, generator);
   }
+  // Display and magnification page.
+  generator->RegisterTopLevelSubpage(
+      IDS_SETTINGS_ACCESSIBILITY_DISPLAY_AND_MAGNIFICATION_LINK_TITLE,
+      mojom::Subpage::kDisplayAndMagnification, mojom::SearchResultIcon::kA11y,
+      mojom::SearchResultDefaultRank::kMedium,
+      mojom::kDisplayAndMagnificationSubpagePath);
+  // Keyboard and text input page.
+  generator->RegisterTopLevelSubpage(
+      IDS_SETTINGS_ACCESSIBILITY_KEYBOARD_AND_TEXT_INPUT_LINK_TITLE,
+      mojom::Subpage::kKeyboardAndTextInput, mojom::SearchResultIcon::kA11y,
+      mojom::SearchResultDefaultRank::kMedium,
+      mojom::kKeyboardAndTextInputSubpagePath);
+  // Cursor and touchpad page.
+  generator->RegisterTopLevelSubpage(
+      IDS_SETTINGS_ACCESSIBILITY_CURSOR_AND_TOUCHPAD_LINK_TITLE,
+      mojom::Subpage::kCursorAndTouchpad, mojom::SearchResultIcon::kA11y,
+      mojom::SearchResultDefaultRank::kMedium,
+      mojom::kCursorAndTouchpadSubpagePath);
+  // Audio and captions page.
+  generator->RegisterTopLevelSubpage(
+      IDS_SETTINGS_ACCESSIBILITY_AUDIO_AND_CAPTIONS_LINK_TITLE,
+      mojom::Subpage::kAudioAndCaptions, mojom::SearchResultIcon::kA11y,
+      mojom::SearchResultDefaultRank::kMedium,
+      mojom::kAudioAndCaptionsSubpagePath);
 
   static constexpr mojom::Setting kManageAccessibilitySettings[] = {
       mojom::Setting::kChromeVox,
@@ -1213,10 +1160,6 @@
         GetA11yFullscreenMagnifierFocusFollowingSearchConcepts());
   }
 
-  if (IsAccessibilityOSSettingsVisibilityEnabled()) {
-    updater.AddSearchTags(GetA11yVisibilitySearchConcepts());
-  }
-
   if (!pref_service_->GetBoolean(prefs::kAccessibilitySwitchAccessEnabled)) {
     return;
   }
diff --git a/chrome/browser/ui/webui/settings/ash/apps_section.cc b/chrome/browser/ui/webui/settings/ash/apps_section.cc
index cf5fc87..3de24ff 100644
--- a/chrome/browser/ui/webui/settings/ash/apps_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/apps_section.cc
@@ -31,7 +31,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui_data_source.h"
-#include "ui/accessibility/accessibility_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/chromeos/devicetype_utils.h"
@@ -445,10 +444,6 @@
       base::FeatureList::IsEnabled(features::kOsSettingsAppBadgingToggle));
   html_source->AddBoolean("showArcvmManageUsb", arc::IsArcVmEnabled());
 
-  html_source->AddBoolean(
-      "isAccessibilityOSSettingsVisibilityEnabled",
-      ::features::IsAccessibilityOSSettingsVisibilityEnabled());
-
   AddAppManagementStrings(html_source);
   AddGuestOsStrings(html_source);
   AddAndroidAppStrings(html_source);
diff --git a/chrome/browser/ui/webui/settings/ash/os_settings_manager_unittest.cc b/chrome/browser/ui/webui/settings/ash/os_settings_manager_unittest.cc
index 66a9715..ae24925 100644
--- a/chrome/browser/ui/webui/settings/ash/os_settings_manager_unittest.cc
+++ b/chrome/browser/ui/webui/settings/ash/os_settings_manager_unittest.cc
@@ -50,10 +50,8 @@
 
   // testing::Test:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures(
-        {features::kAccessibilityOSSettingsVisibility,
-         features::kAccessibilitySelectToSpeakPageMigration},
-        {});
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kAccessibilitySelectToSpeakPageMigration);
 
     ASSERT_TRUE(profile_manager_.SetUp());
     TestingProfile* profile =
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index c7e9d09..d7f3c78 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -91,7 +91,6 @@
 #include "net/net_buildflags.h"
 #include "services/device/public/cpp/device_features.h"
 #include "third_party/blink/public/common/features_generated.h"
-#include "ui/accessibility/accessibility_features.h"
 #include "ui/accessibility/accessibility_switches.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -116,6 +115,7 @@
 #include "ui/chromeos/devicetype_utils.h"
 #else  // !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/webui/settings/system_handler.h"
+#include "ui/accessibility/accessibility_features.h"
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -266,11 +266,7 @@
                           base::win::GetVersion() >= base::win::Version::WIN10);
 #endif
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  html_source->AddBoolean("isAccessibilityOSSettingsVisibilityEnabled",
-                          base::FeatureList::IsEnabled(
-                              features::kAccessibilityOSSettingsVisibility));
-#else
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddBoolean(
       "showFocusHighlightOption",
       base::FeatureList::IsEnabled(features::kAccessibilityFocusHighlight));
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 51f4dc9..af3cc6e 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1669118022-f121e883b2d8cf47cec9a92bf3539af456cfc29d.profdata
+chrome-mac-main-1669139889-aedfce4c631058bfa133fc19f996331b8d857528.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 77a862b..2a4fa72a 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1669107124-7086c711c1a80fa3be9c7d331e560997571c4033.profdata
+chrome-win32-main-1669118022-7d733e0712cb7443c62cc67d4bb74a8b7c02b7a6.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index aac35fd..14248f73 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1669096145-2a4c8c0b5ad39763533a2361c388f13dc1cf1ea1.profdata
+chrome-win64-main-1669129049-07cf842809d14c8c9a373e35549016b5d65d5630.profdata
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index 6b49f5b24..caaadbc 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -46,6 +46,7 @@
 #include "chrome/installer/setup/setup_constants.h"
 #include "chrome/installer/setup/setup_util.h"
 #include "chrome/installer/setup/update_active_setup_version_work_item.h"
+#include "chrome/installer/util/app_command.h"
 #include "chrome/installer/util/callback_work_item.h"
 #include "chrome/installer/util/conditional_work_item_list.h"
 #include "chrome/installer/util/create_reg_key_work_item.h"
@@ -331,9 +332,6 @@
   if (!installer_state.system_install())
     return;
 
-  const HKEY root_key = installer_state.root_key();
-  const std::wstring cmd_key(GetCommandKey(kCmdStoreDMToken));
-
   // Register a command to allow Chrome to request Google Update to run
   // setup.exe --store-dmtoken=<token>, which will store the specified token
   // in the registry.
@@ -349,13 +347,14 @@
   // safety check for unsafe insert sequences since the right thing is
   // happening. Do not blindly copy this pattern in new code. Check with a
   // member of base/win/OWNERS if in doubt.
-  AppCommand cmd(cmd_line.GetCommandLineStringWithUnsafeInsertSequences());
+  AppCommand cmd(kCmdStoreDMToken,
+                 cmd_line.GetCommandLineStringWithUnsafeInsertSequences());
 
   // TODO(rogerta): For now setting this command as web accessible is required
   // by Google Update.  Could revisit this should Google Update change the
   // way permissions are handled for commands.
   cmd.set_is_web_accessible(true);
-  cmd.AddWorkItems(root_key, cmd_key, install_list);
+  cmd.AddCreateAppCommandWorkItems(installer_state.root_key(), install_list);
 }
 
 // Adds work items to add the "delete-dmtoken" command to Chrome's version key.
@@ -369,9 +368,6 @@
   if (!installer_state.system_install())
     return;
 
-  const HKEY root_key = installer_state.root_key();
-  const std::wstring cmd_key(GetCommandKey(kCmdDeleteDMToken));
-
   // Register a command to allow Chrome to request Google Update to run
   // setup.exe --delete-dmtoken, which will delete any existing DMToken from the
   // registry.
@@ -381,13 +377,13 @@
   cmd_line.AppendSwitch(switches::kSystemLevel);
   cmd_line.AppendSwitch(switches::kVerboseLogging);
   InstallUtil::AppendModeAndChannelSwitches(&cmd_line);
-  AppCommand cmd(cmd_line.GetCommandLineString());
+  AppCommand cmd(kCmdDeleteDMToken, cmd_line.GetCommandLineString());
 
   // TODO(rogerta): For now setting this command as web accessible is required
   // by Google Update.  Could revisit this should Google Update change the
   // way permissions are handled for commands.
   cmd.set_is_web_accessible(true);
-  cmd.AddWorkItems(root_key, cmd_key, install_list);
+  cmd.AddCreateAppCommandWorkItems(installer_state.root_key(), install_list);
 }
 
 // Adds work items to add the "rotate-dtkey" command to Chrome's version key.
@@ -400,9 +396,6 @@
   if (!installer_state.system_install())
     return;
 
-  const HKEY root_key = installer_state.root_key();
-  const std::wstring cmd_key(GetCommandKey(kCmdRotateDeviceTrustKey));
-
   // Register a command to allow Chrome to request Google Update to run
   // setup.exe --rotate-dtkey=<dm-token>, which will rotate the key and store
   // it in the registry.
@@ -420,13 +413,14 @@
   // safety check for unsafe insert sequences since the right thing is
   // happening. Do not blindly copy this pattern in new code. Check with a
   // member of base/win/OWNERS if in doubt.
-  AppCommand cmd(cmd_line.GetCommandLineStringWithUnsafeInsertSequences());
+  AppCommand cmd(kCmdRotateDeviceTrustKey,
+                 cmd_line.GetCommandLineStringWithUnsafeInsertSequences());
 
   // TODO(rogerta): For now setting this command as web accessible is required
   // by Google Update.  Could revisit this should Google Update change the
   // way permissions are handled for commands.
   cmd.set_is_web_accessible(true);
-  cmd.AddWorkItems(root_key, cmd_key, install_list);
+  cmd.AddCreateAppCommandWorkItems(installer_state.root_key(), install_list);
 }
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
@@ -665,7 +659,7 @@
           google_update::kRegCriticalVersionField);
     }
 
-    // Form the mode-specific rename command.
+    // Form the mode-specific rename command and register it.
     base::CommandLine product_rename_cmd(installer_path);
     product_rename_cmd.AppendSwitch(switches::kRenameChromeExe);
     if (installer_state.system_install())
@@ -673,9 +667,9 @@
     if (installer_state.verbose_logging())
       product_rename_cmd.AppendSwitch(switches::kVerboseLogging);
     InstallUtil::AppendModeAndChannelSwitches(&product_rename_cmd);
-    in_use_update_work_items->AddSetRegValueWorkItem(
-        root, clients_key, KEY_WOW64_32KEY, google_update::kRegRenameCmdField,
-        product_rename_cmd.GetCommandLineString(), true);
+    AppCommand(installer::kCmdRenameChromeExe,
+               product_rename_cmd.GetCommandLineString())
+        .AddCreateAppCommandWorkItems(root, in_use_update_work_items.get());
 
     // Delay deploying the new chrome_proxy while chrome is running.
     in_use_update_work_items->AddCopyTreeWorkItem(
@@ -706,8 +700,8 @@
     regular_update_work_items->AddDeleteRegValueWorkItem(
         root, clients_key, KEY_WOW64_32KEY,
         google_update::kRegCriticalVersionField);
-    regular_update_work_items->AddDeleteRegValueWorkItem(
-        root, clients_key, KEY_WOW64_32KEY, google_update::kRegRenameCmdField);
+    AppCommand(installer::kCmdRenameChromeExe, {})
+        .AddDeleteAppCommandWorkItems(root, regular_update_work_items.get());
 
     // Only copy chrome_proxy.exe directly when chrome.exe isn't in use to avoid
     // different versions getting mixed up between the two binaries.
@@ -1057,11 +1051,10 @@
                            const base::Version& new_version,
                            WorkItemList* install_list) {
   const HKEY root_key = installer_state.root_key();
-  const std::wstring cmd_key(GetCommandKey(kCmdOnOsUpgrade));
 
   if (installer_state.operation() == InstallerState::UNINSTALL) {
-    install_list->AddDeleteRegKeyWorkItem(root_key, cmd_key, KEY_WOW64_32KEY)
-        ->set_log_message("Removing OS upgrade command");
+    AppCommand(kCmdOnOsUpgrade, {})
+        .AddDeleteAppCommandWorkItems(root_key, install_list);
   } else {
     // Register with Google Update to have setup.exe --on-os-upgrade called on
     // OS upgrade.
@@ -1076,9 +1069,9 @@
     // Log everything for now.
     cmd_line.AppendSwitch(installer::switches::kVerboseLogging);
 
-    AppCommand cmd(cmd_line.GetCommandLineString());
+    AppCommand cmd(kCmdOnOsUpgrade, cmd_line.GetCommandLineString());
     cmd.set_is_auto_run_on_os_upgrade(true);
-    cmd.AddWorkItems(installer_state.root_key(), cmd_key, install_list);
+    cmd.AddCreateAppCommandWorkItems(root_key, install_list);
   }
 }
 
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 206154a8..22ebc3d 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -74,6 +74,7 @@
 #include "chrome/installer/setup/setup_util.h"
 #include "chrome/installer/setup/uninstall.h"
 #include "chrome/installer/setup/user_experiment.h"
+#include "chrome/installer/util/app_command.h"
 #include "chrome/installer/util/conditional_work_item_list.h"
 #include "chrome/installer/util/delete_after_reboot_helper.h"
 #include "chrome/installer/util/delete_old_versions.h"
@@ -583,9 +584,8 @@
   install_list->AddDeleteRegValueWorkItem(
       reg_root, clients_key, KEY_WOW64_32KEY,
       google_update::kRegCriticalVersionField);
-  install_list->AddDeleteRegValueWorkItem(reg_root, clients_key,
-                                          KEY_WOW64_32KEY,
-                                          google_update::kRegRenameCmdField);
+  installer::AppCommand(installer::kCmdRenameChromeExe, {})
+      .AddDeleteAppCommandWorkItems(reg_root, install_list.get());
 
   // If a channel was specified by policy, update the "channel" registry value
   // with it so that the browser knows which channel to use, otherwise delete
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 89881f2..af8dc18 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -47,6 +47,7 @@
 #include "chrome/installer/setup/installer_state.h"
 #include "chrome/installer/setup/setup_constants.h"
 #include "chrome/installer/setup/user_hive_visitor.h"
+#include "chrome/installer/util/app_command.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/google_update_settings.h"
 #include "chrome/installer/util/initial_preferences.h"
@@ -121,9 +122,10 @@
 void RemoveLegacyChromeAppCommands(const InstallerState& installer_state) {
 // These app commands were only registered for Google Chrome.
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-  installer::DeleteRegistryKey(installer_state.root_key(),
-                               GetCommandKey(L"install-extension"),
-                               KEY_WOW64_32KEY);
+  std::unique_ptr<WorkItemList> list(WorkItem::CreateWorkItemList());
+  AppCommand(L"install-extension", {})
+      .AddDeleteAppCommandWorkItems(installer_state.root_key(), list.get());
+  list->Do();
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
@@ -375,15 +377,6 @@
 #endif
 }
 
-std::wstring GetCommandKey(const wchar_t* name) {
-  std::wstring cmd_key = install_static::GetClientsKeyPath();
-  cmd_key.append(1, base::FilePath::kSeparators[0])
-      .append(google_update::kRegCommandsKey)
-      .append(1, base::FilePath::kSeparators[0])
-      .append(name);
-  return cmd_key;
-}
-
 void DeleteRegistryKeyPartial(
     HKEY root,
     const std::wstring& path,
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h
index d52a25f..442632a 100644
--- a/chrome/installer/setup/setup_util.h
+++ b/chrome/installer/setup/setup_util.h
@@ -103,9 +103,6 @@
 // Returns true if the processor is supported by chrome.
 bool IsProcessorSupported();
 
-// Returns the "...\\Commands\\|name|" registry key for a product's |reg_data|.
-std::wstring GetCommandKey(const wchar_t* name);
-
 // Deletes all values and subkeys of the key |path| under |root|, preserving
 // the keys named in |keys_to_preserve| (each of which must be an ASCII string).
 // The key itself is deleted if no subkeys are preserved.
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index 788d975..e3e4c04c 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -539,12 +539,6 @@
       base::CommandLine::FromString(L"foo.exe --chrome-frame")));
 }
 
-TEST(SetupUtilTest, GetRegistrationDataCommandKey) {
-  const std::wstring key = installer::GetCommandKey(L"test_name");
-  EXPECT_TRUE(base::EndsWith(key, L"\\Commands\\test_name",
-                             base::CompareCase::SENSITIVE));
-}
-
 TEST(SetupUtilTest, GetConsoleSessionStartTime) {
   base::Time start_time = installer::GetConsoleSessionStartTime();
   EXPECT_FALSE(start_time.is_null());
diff --git a/chrome/installer/util/BUILD.gn b/chrome/installer/util/BUILD.gn
index df0d6423..f03fa4f 100644
--- a/chrome/installer/util/BUILD.gn
+++ b/chrome/installer/util/BUILD.gn
@@ -364,7 +364,6 @@
       "//chrome/common:constants",
       "//chrome/install_static:install_static_util",
       "//chrome/install_static/test:test_support",
-      "//chrome/installer/setup:lib",
       "//chrome/installer/test:alternate_version_generator_lib",
       "//components/variations",
       "//components/version_info:channel",
diff --git a/chrome/installer/util/app_command.cc b/chrome/installer/util/app_command.cc
index 4f32fb8..65bf394 100644
--- a/chrome/installer/util/app_command.cc
+++ b/chrome/installer/util/app_command.cc
@@ -4,15 +4,31 @@
 
 #include "chrome/installer/util/app_command.h"
 
+#include <windows.h>
+
 #include <stddef.h>
 
+#include "base/check.h"
 #include "base/logging.h"
+#include "base/strings/strcat.h"
 #include "base/win/registry.h"
+#include "chrome/install_static/install_util.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/work_item_list.h"
 
 namespace installer {
 
+namespace {
+
+// Returns the "`GetClientsKeyPath()`\\Commands\\`name`" registry key path used
+// to register AppCommands with the updater.
+std::wstring GetCommandKey(const std::wstring& name) {
+  return base::StrCat({install_static::GetClientsKeyPath(), L"\\",
+                       google_update::kRegCommandsKey, L"\\", name});
+}
+
+}  // namespace
+
 // static
 // Associate bool member variables with registry entries.
 const AppCommand::NamedBoolVar AppCommand::kNameBoolVars[] = {
@@ -29,13 +45,34 @@
       is_auto_run_on_os_upgrade_(false),
       is_run_as_user_(false) {}
 
-AppCommand::AppCommand(const std::wstring& command_line)
-    : command_line_(command_line),
+AppCommand::AppCommand(const std::wstring& command_name,
+                       const std::wstring& command_line)
+    : command_name_(command_name),
+      command_line_(command_line),
       sends_pings_(false),
       is_web_accessible_(false),
       is_auto_run_on_os_upgrade_(false),
       is_run_as_user_(false) {}
 
+AppCommand::AppCommand(AppCommand&&) = default;
+AppCommand::AppCommand(const AppCommand&) = default;
+AppCommand::~AppCommand() = default;
+
+bool AppCommand::Initialize(HKEY root_key) {
+  DCHECK(!command_name_.empty());
+
+  base::win::RegKey key;
+  auto result = key.Open(root_key, GetCommandKey(command_name_).c_str(),
+                         KEY_QUERY_VALUE | KEY_WOW64_32KEY);
+  if (result != ERROR_SUCCESS) {
+    ::SetLastError(result);
+    PLOG(DFATAL) << "Error opening AppCommand: " << command_name_;
+    return false;
+  }
+
+  return Initialize(key);
+}
+
 bool AppCommand::Initialize(const base::win::RegKey& key) {
   if (!key.Valid()) {
     LOG(DFATAL) << "Cannot initialize an AppCommand from an invalid key.";
@@ -64,16 +101,16 @@
   return true;
 }
 
-void AppCommand::AddWorkItems(HKEY predefined_root,
-                              const std::wstring& command_path,
-                              WorkItemList* item_list) const {
-  // Command_path is derived from GetRegCommandKey which always returns
-  // value from GetClientsKeyPath() which should be 32-bit hive.
-  item_list
-      ->AddCreateRegKeyWorkItem(predefined_root, command_path, KEY_WOW64_32KEY)
+void AppCommand::AddCreateAppCommandWorkItems(const HKEY root_key,
+                                              WorkItemList* item_list) const {
+  DCHECK(!command_name_.empty());
+  DCHECK(!command_line_.empty());
+
+  const std::wstring command_path = GetCommandKey(command_name_);
+  item_list->AddCreateRegKeyWorkItem(root_key, command_path, KEY_WOW64_32KEY)
       ->set_log_message("creating AppCommand registry key");
   item_list
-      ->AddSetRegValueWorkItem(predefined_root, command_path, KEY_WOW64_32KEY,
+      ->AddSetRegValueWorkItem(root_key, command_path, KEY_WOW64_32KEY,
                                google_update::kRegCommandLineField,
                                command_line_, true)
       ->set_log_message("setting AppCommand CommandLine registry value");
@@ -85,14 +122,21 @@
     // Adds a work item to set |var_name| to DWORD 1 if |var_data| is true;
     // adds a work item to remove |var_name| otherwise.
     if (var_data) {
-      item_list->AddSetRegValueWorkItem(predefined_root, command_path,
-                                        KEY_WOW64_32KEY, var_name,
-                                        static_cast<DWORD>(1), true);
+      item_list->AddSetRegValueWorkItem(root_key, command_path, KEY_WOW64_32KEY,
+                                        var_name, static_cast<DWORD>(1), true);
     } else {
-      item_list->AddDeleteRegValueWorkItem(predefined_root, command_path,
+      item_list->AddDeleteRegValueWorkItem(root_key, command_path,
                                            KEY_WOW64_32KEY, var_name);
     }
   }
 }
 
+void AppCommand::AddDeleteAppCommandWorkItems(const HKEY root_key,
+                                              WorkItemList* item_list) const {
+  DCHECK(!command_name_.empty());
+
+  item_list->AddDeleteRegKeyWorkItem(root_key, GetCommandKey(command_name_),
+                                     KEY_WOW64_32KEY);
+}
+
 }  // namespace installer
diff --git a/chrome/installer/util/app_command.h b/chrome/installer/util/app_command.h
index 31974d5..1052f07 100644
--- a/chrome/installer/util/app_command.h
+++ b/chrome/installer/util/app_command.h
@@ -25,19 +25,33 @@
 class AppCommand {
  public:
   AppCommand();
-  // Constructs a new command that will execute the given |command_line|.
+
+  // Constructs a new command with the given `command_name` and `command_line`.
   // All other properties default to false.
-  explicit AppCommand(const std::wstring& command_line);
-  // The implicit dtor, copy ctor and assignment operator are desired.
+  AppCommand(const std::wstring& command_name,
+             const std::wstring& command_line);
+
+  // The default copy ctors, dtor, and assignment operators are desired.
+  AppCommand(AppCommand&&);
+  AppCommand(const AppCommand&);
+  ~AppCommand();
+  AppCommand& operator=(AppCommand&&) = default;
+  AppCommand& operator=(const AppCommand&) = default;
+
+  // Initializes an instance from the command in
+  // `root_key`\Google\Update\Clients\{`app_id`}\Commands\`command_name_`
+  bool Initialize(HKEY root_key);
 
   // Initializes an instance from the command in |key|.
   bool Initialize(const base::win::RegKey& key);
 
-  // Adds to |item_list| work items to write this object to the key named
-  // |command_path| under |predefined_root|.
-  void AddWorkItems(HKEY predefined_root,
-                    const std::wstring& command_path,
-                    WorkItemList* item_list) const;
+  // Adds to `item_list` work items to write the command under `root_key`.
+  void AddCreateAppCommandWorkItems(const HKEY root_key,
+                                    WorkItemList* item_list) const;
+
+  // Adds to `item_list` work items to delete the command under `root_key`.
+  void AddDeleteAppCommandWorkItems(const HKEY root_key,
+                                    WorkItemList* item_list) const;
 
   // Returns the command-line for the app command as it is represented in the
   // registry.  Use CommandLine::FromString() on this value to check arguments
@@ -66,6 +80,7 @@
   }
 
  protected:
+  std::wstring command_name_;
   std::wstring command_line_;
   bool sends_pings_;
   bool is_web_accessible_;
diff --git a/chrome/installer/util/google_update_constants.cc b/chrome/installer/util/google_update_constants.cc
index f7cefca..9eb33bd 100644
--- a/chrome/installer/util/google_update_constants.cc
+++ b/chrome/installer/util/google_update_constants.cc
@@ -60,7 +60,6 @@
 const wchar_t kRegRLZBrandField[] = L"brand";
 const wchar_t kRegRLZReactivationBrandField[] = L"reactivationbrand";
 const wchar_t kRegReferralField[] = L"referral";
-const wchar_t kRegRenameCmdField[] = L"cmd";
 const wchar_t kRegRunAsUserField[] = L"RunAsUser";
 const wchar_t kRegSendsPingsField[] = L"SendsPings";
 const wchar_t kRegUninstallCmdLine[] = L"UninstallCmdLine";
diff --git a/chrome/installer/util/google_update_constants.h b/chrome/installer/util/google_update_constants.h
index 6aeb3d8f..9d93d0dc8 100644
--- a/chrome/installer/util/google_update_constants.h
+++ b/chrome/installer/util/google_update_constants.h
@@ -76,7 +76,6 @@
 extern const wchar_t kRegRLZBrandField[];
 extern const wchar_t kRegRLZReactivationBrandField[];
 extern const wchar_t kRegReferralField[];
-extern const wchar_t kRegRenameCmdField[];
 extern const wchar_t kRegRunAsUserField[];
 extern const wchar_t kRegSendsPingsField[];
 extern const wchar_t kRegUninstallCmdLine[];
diff --git a/chrome/installer/util/installation_state.cc b/chrome/installer/util/installation_state.cc
index 0e5c9070..c974226 100644
--- a/chrome/installer/util/installation_state.cc
+++ b/chrome/installer/util/installation_state.cc
@@ -12,6 +12,7 @@
 #include "base/version.h"
 #include "base/win/registry.h"
 #include "chrome/install_static/install_util.h"
+#include "chrome/installer/util/app_commands.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/util_constants.h"
@@ -80,7 +81,6 @@
         old_version_.reset();
     }
 
-    key.ReadValue(google_update::kRegRenameCmdField, &rename_cmd_);
     if (!InitializeCommands(key, &commands_))
       commands_.Clear();
   }
@@ -155,7 +155,6 @@
                          ? new base::Version(*other.old_version_)
                          : nullptr);
   brand_ = other.brand_;
-  rename_cmd_ = other.rename_cmd_;
   uninstall_command_ = other.uninstall_command_;
   oem_install_ = other.oem_install_;
   commands_.CopyFrom(other.commands_);
@@ -173,7 +172,6 @@
   version_.reset();
   old_version_.reset();
   brand_.clear();
-  rename_cmd_.clear();
   oem_install_.clear();
   uninstall_command_ = base::CommandLine(base::CommandLine::NO_PROGRAM);
   commands_.Clear();
diff --git a/chrome/installer/util/installation_state.h b/chrome/installer/util/installation_state.h
index 6ff3831c..80828ce 100644
--- a/chrome/installer/util/installation_state.h
+++ b/chrome/installer/util/installation_state.h
@@ -53,10 +53,6 @@
   // Returns the brand code the product is currently installed with.
   const std::wstring& brand() const { return brand_; }
 
-  // Returns the command to be used to update to the new version that is
-  // awaiting update; may be empty.
-  const std::wstring& rename_cmd() const { return rename_cmd_; }
-
   // Returns true and populates |eula_accepted| if the product has such a value;
   // otherwise, returns false and does not modify |eula_accepted|.  Expected
   // values are 0 (false) and 1 (true), although |eula_accepted| is given
@@ -95,7 +91,6 @@
   std::unique_ptr<base::Version> version_;
   std::unique_ptr<base::Version> old_version_;
   std::wstring brand_;
-  std::wstring rename_cmd_;
   std::wstring oem_install_;
   base::CommandLine uninstall_command_;
   AppCommands commands_;
diff --git a/chrome/installer/util/product_state_unittest.cc b/chrome/installer/util/product_state_unittest.cc
index 642fab1..1bb0ca3 100644
--- a/chrome/installer/util/product_state_unittest.cc
+++ b/chrome/installer/util/product_state_unittest.cc
@@ -154,39 +154,6 @@
   }
 }
 
-// Test extraction of the "cmd" value from the Clients key.
-TEST_P(ProductStateTest, InitializeRenameCmd) {
-  MinimallyInstallProduct(L"10.0.1.1");
-
-  // No "cmd" value.
-  {
-    ProductState state;
-    LONG result = clients_.DeleteValue(google_update::kRegRenameCmdField);
-    EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
-    EXPECT_TRUE(state.Initialize(system_install_));
-    EXPECT_TRUE(state.rename_cmd().empty());
-  }
-
-  // Empty "cmd" value.
-  {
-    ProductState state;
-    LONG result = clients_.WriteValue(google_update::kRegRenameCmdField, L"");
-    EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
-    EXPECT_TRUE(state.Initialize(system_install_));
-    EXPECT_TRUE(state.rename_cmd().empty());
-  }
-
-  // Valid "cmd" value.
-  {
-    ProductState state;
-    LONG result = clients_.WriteValue(google_update::kRegRenameCmdField,
-                                      L"spam.exe --spamalot");
-    EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
-    EXPECT_TRUE(state.Initialize(system_install_));
-    EXPECT_EQ(L"spam.exe --spamalot", state.rename_cmd());
-  }
-}
-
 // Test extraction of the uninstall command and arguments from the ClientState
 // key.
 TEST_P(ProductStateTest, InitializeUninstallCommand) {
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index d530d89..1eb6052 100644
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -223,6 +223,7 @@
 const wchar_t kChromeProxyExe[] = L"chrome_proxy.exe";
 const wchar_t kChromeProxyNewExe[] = L"new_chrome_proxy.exe";
 const wchar_t kChromeProxyOldExe[] = L"old_chrome_proxy.exe";
+const wchar_t kCmdRenameChromeExe[] = L"rename-chrome-exe";
 const wchar_t kCmdOnOsUpgrade[] = L"on-os-upgrade";
 const wchar_t kCmdRotateDeviceTrustKey[] = L"rotate-dtkey";
 const wchar_t kCmdStoreDMToken[] = L"store-dmtoken";
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index a632d17..2366e35 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -226,6 +226,7 @@
 extern const wchar_t kChromeProxyExe[];
 extern const wchar_t kChromeProxyNewExe[];
 extern const wchar_t kChromeProxyOldExe[];
+extern const wchar_t kCmdRenameChromeExe[];
 extern const wchar_t kCmdOnOsUpgrade[];
 extern const wchar_t kCmdRotateDeviceTrustKey[];
 extern const wchar_t kCmdStoreDMToken[];
diff --git a/chrome/test/data/android/view_transition.html b/chrome/test/data/android/view_transition.html
new file mode 100644
index 0000000..080e2fbb
--- /dev/null
+++ b/chrome/test/data/android/view_transition.html
@@ -0,0 +1,134 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <script>
+      const params = new URLSearchParams(window.location.search);
+      let metaTagContent = 'width=device-width,minimum-scale=1';
+      if (params.has('resizes-content'))
+        metaTagContent += ',interactive-widget=resizes-content';
+      else if (params.has('resizes-visual'))
+        metaTagContent += ',interactive-widget=resizes-visual';
+      else if (params.has('overlays-content')) {
+        metaTagContent += ',interactive-widget=overlays-content';
+      }
+
+      let meta = document.createElement('meta');
+      meta.name = 'viewport';
+      meta.content = metaTagContent;
+      document.head.appendChild(meta);
+
+      if (params.has('new'))
+        document.documentElement.classList.add('new');
+      else if (params.has('old'))
+        document.documentElement.classList.add('old');
+    </script>
+    <style>
+      input {
+        /* Invisible so that blinking cursor doesn't affect pixel tests */
+        position: absolute;
+        top: 50px;
+        opacity: 0;
+      }
+
+      #bottomfixed {
+        position: fixed;
+        left: 20px;
+        bottom: 10px;
+        width: 100px;
+        height: 30px;
+        background-color: coral;
+        view-transition-name: bottom;
+        contain: paint;
+      }
+
+      #topfixed {
+        position: fixed;
+        left: 20px;
+        top: 10px;
+        width: 100px;
+        height: 30px;
+        background-color: dodgerblue;
+        view-transition-name: top;
+        contain: paint;
+      }
+
+      #inflow {
+        position: absolute;
+        left: 100px;
+        top: 200px;
+        width: 100px;
+        height: 300px;
+        background-color: rebeccapurple;
+      }
+
+      /* For live testing - if no class is set on the root use the regular but
+       * slow transition */
+      ::view-transition-group(*),
+      ::view-transition-new(*),
+      ::view-transition-old(*) {
+        animation-duration: 5s;
+      }
+
+      /* Step function and long duration means we'll simply keep the snapshots
+       * in their initial state for 30 seconds so the pixel test can take a
+       * screenshot reliably. */
+      .old::view-transition-group(*),
+      .old::view-transition-new(*),
+      .old::view-transition-old(*) {
+        animation-duration: 30s;
+        animation-direction: normal;
+        animation-timing-function: steps(1, end);
+      }
+
+      /* Reverse the direction if we're capturing the new state */
+      .new::view-transition-group(*),
+      .new::view-transition-new(*),
+      .new::view-transition-old(*) {
+        animation-duration: 30s;
+        animation-direction: reverse;
+        animation-timing-function: steps(1, start);
+      }
+    </style>
+    <script>
+      let transition = null;
+
+      // Allow tests to control when the transition starts.
+      let startTransitionAnimation = null;
+      let startPromise = new Promise(resolve => {startTransitionAnimation = resolve;});
+
+      // Allow tests to wait until the snapshot has been taken and is ready to
+      // start transitioning.
+      let readyToStartResolve = null;
+      let readyToStartPromise = new Promise(resolve => {readyToStartResolve = resolve;});
+
+      function updateDOM() {
+        document.getElementById("inflow").style.transform = "translateX(100px)";
+        document.getElementById("bottomfixed").style.transform = "translateX(100px)";
+        document.getElementById("topfixed").style.transform = "translateX(100px)";
+      }
+
+      function undoUpdateDOM() {
+        document.getElementById("inflow").style = "";
+        document.getElementById("bottomfixed").style = "";
+        document.getElementById("topfixed").style = "";
+      }
+
+      function createTransition() {
+        transition = document.startViewTransition(() => {
+          updateDOM();
+
+          readyToStartResolve();
+
+          return startPromise;
+        });
+
+      }
+    </script>
+  </head>
+  <body>
+    <input id="inputElement" type="text">
+    <div id="inflow"></div>
+    <div id="bottomfixed"></div>
+    <div id="topfixed"></div>
+  </body>
+</html>
diff --git a/chrome/test/data/webui/chromeos/diagnostics/keyboard_tester_test.js b/chrome/test/data/webui/chromeos/diagnostics/keyboard_tester_test.js
index c6259609..638a6fa 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/keyboard_tester_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/keyboard_tester_test.js
@@ -9,10 +9,11 @@
 import {ConnectionType, KeyEvent, KeyEventType, MechanicalLayout, NumberPadPresence, PhysicalLayout, TopRightKey} from 'chrome://diagnostics/input_data_provider.mojom-webui.js';
 import {TopRightKey as DiagramTopRightKey} from 'chrome://resources/ash/common/keyboard_diagram.js';
 import {KeyboardKeyState} from 'chrome://resources/ash/common/keyboard_key.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
+import {MockTimer} from 'chrome://webui-test/mock_timer.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 import {eventToPromise} from 'chrome://webui-test/test_util.js';
 
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
 import {MockController} from '../mock_controller.m.js';
 import {isVisible} from '../test_util.js';
 
@@ -181,12 +182,17 @@
   test('focusLossToast', async () => {
     keyboardTesterElement.keyboard = fakeKeyboard;
     await flushTasks();
+    const mockTimer = new MockTimer();
+    mockTimer.install();
+    keyboardTesterElement.keyboard = fakeKeyboard;
 
     keyboardTesterElement.onKeyEventsPaused();
     assertTrue(keyboardTesterElement.$.lostFocusToast.open);
 
     keyboardTesterElement.onKeyEventsResumed();
+    mockTimer.tick(1000);
     assertFalse(keyboardTesterElement.$.lostFocusToast.open);
+    mockTimer.uninstall();
   });
 
   test('closeOnExitShortcut', async () => {
diff --git a/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js b/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js
index a9d1867..d383776 100644
--- a/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js
@@ -60,7 +60,9 @@
     deviceBrowserProxy.hasPointingStick = false;
     DevicePageBrowserProxyImpl.setInstanceForTesting(deviceBrowserProxy);
 
+    loadTimeData.overrideValues({isKioskModeActive: true});
     PolymerTest.clearBody();
+    Router.getInstance().navigateTo(routes.MANAGE_ACCESSIBILITY);
   });
 
   teardown(function() {
@@ -70,123 +72,6 @@
     Router.getInstance().resetRouteForTesting();
   });
 
-  test('Pointers row only visible if mouse/touchpad present', function() {
-    initPage();
-    const row = page.shadowRoot.querySelector('#pointerSubpageButton');
-    assertFalse(row.hidden);
-
-    // Has touchpad, doesn't have mouse ==> not hidden.
-    deviceBrowserProxy.hasMouse = false;
-    assertFalse(row.hidden);
-
-    // Doesn't have either ==> hidden.
-    deviceBrowserProxy.hasTouchpad = false;
-    assertTrue(row.hidden);
-
-    // Has mouse, doesn't have touchpad ==> not hidden.
-    deviceBrowserProxy.hasMouse = true;
-    assertFalse(row.hidden);
-
-    // Has both ==> not hidden.
-    deviceBrowserProxy.hasTouchpad = true;
-    assertFalse(row.hidden);
-  });
-
-  test('tablet mode buttons visible', function() {
-    loadTimeData.overrideValues({
-      isKioskModeActive: false,
-      showTabletModeShelfNavigationButtonsSettings: true,
-    });
-    initPage();
-    flush();
-
-    assertTrue(isVisible(page.shadowRoot.querySelector(
-        '#shelfNavigationButtonsEnabledControl')));
-  });
-
-  test('toggle tablet mode buttons', function() {
-    loadTimeData.overrideValues({
-      isKioskModeActive: false,
-      showTabletModeShelfNavigationButtonsSettings: true,
-    });
-    initPage();
-    flush();
-
-    const navButtonsToggle =
-        page.shadowRoot.querySelector('#shelfNavigationButtonsEnabledControl');
-    assertTrue(isVisible(navButtonsToggle));
-    // The default pref value is false.
-    assertFalse(navButtonsToggle.checked);
-
-    // Clicking the toggle should update the toggle checked value, and the
-    // backing preference.
-    navButtonsToggle.click();
-    flush();
-
-    assertTrue(navButtonsToggle.checked);
-    assertFalse(navButtonsToggle.disabled);
-    assertTrue(
-        page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value);
-
-    navButtonsToggle.click();
-    flush();
-
-    assertFalse(navButtonsToggle.checked);
-    assertFalse(navButtonsToggle.disabled);
-    assertFalse(
-        page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value);
-  });
-
-  test('tablet mode buttons toggle disabled with spoken feedback', function() {
-    loadTimeData.overrideValues({
-      isKioskModeActive: false,
-      showTabletModeShelfNavigationButtonsSettings: true,
-    });
-
-    const prefs = getDefaultPrefs();
-    // Enable spoken feedback.
-    prefs.settings.accessibility.value = true;
-
-    initPage(prefs);
-    flush();
-
-    const navButtonsToggle =
-        page.shadowRoot.querySelector('#shelfNavigationButtonsEnabledControl');
-    assertTrue(isVisible(navButtonsToggle));
-
-    // If spoken feedback is enabled, the shelf nav buttons toggle should be
-    // disabled and checked.
-    assertTrue(navButtonsToggle.disabled);
-    assertTrue(navButtonsToggle.checked);
-
-    // Clicking the toggle should have no effect.
-    navButtonsToggle.click();
-    flush();
-
-    assertTrue(navButtonsToggle.disabled);
-    assertTrue(navButtonsToggle.checked);
-    assertFalse(
-        page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value);
-
-    // The toggle should be enabled if the spoken feedback gets disabled.
-    page.set('prefs.settings.accessibility.value', false);
-    flush();
-
-    assertFalse(!!navButtonsToggle.disabled);
-    assertFalse(navButtonsToggle.checked);
-    assertFalse(
-        page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value);
-
-    // Clicking the toggle should update the backing pref.
-    navButtonsToggle.click();
-    flush();
-
-    assertFalse(!!navButtonsToggle.disabled);
-    assertTrue(navButtonsToggle.checked);
-    assertTrue(
-        page.prefs.settings.a11y.tablet_mode_shelf_nav_buttons_enabled.value);
-  });
-
   test('some parts are hidden in kiosk mode', function() {
     loadTimeData.overrideValues({
       isKioskModeActive: true,
@@ -224,26 +109,6 @@
     assertFalse(isVisible(page.$.additionalFeaturesLink));
   });
 
-  test('Deep link to switch access', async () => {
-    loadTimeData.overrideValues({
-      isKioskModeActive: false,
-    });
-    initPage();
-
-    const params = new URLSearchParams();
-    params.append('settingId', '1522');
-    Router.getInstance().navigateTo(routes.MANAGE_ACCESSIBILITY, params);
-
-    flush();
-
-    const deepLinkElement = page.shadowRoot.querySelector('#enableSwitchAccess')
-                                .shadowRoot.querySelector('cr-toggle');
-    await waitAfterNextRender(deepLinkElement);
-    assertEquals(
-        deepLinkElement, getDeepActiveElement(),
-        'Switch access toggle should be focused for settingId=1522.');
-  });
-
   test('Dictation labels', async () => {
     // Ensure that the Dictation locale menu is shown by setting the dictation
     // pref to true (done in default prefs) and populating dictation locale
@@ -362,53 +227,4 @@
         'French (France) speech is sent to Google for processing',
         page.computeDictationLocaleSubtitle_());
   });
-
-  [true, false].forEach(isAccessibilityOSSettingsVisibilityEnabled => {
-    loadTimeData.overrideValues({isAccessibilityOSSettingsVisibilityEnabled});
-
-    const selectorRouteList = [
-      {
-        selector: '#captionsSubpageButton',
-        route: routes.MANAGE_CAPTION_SETTINGS,
-      },
-      {selector: '#displaySubpageButton', route: routes.DISPLAY},
-      {selector: '#keyboardSubpageButton', route: routes.KEYBOARD},
-      {selector: '#pointerSubpageButton', route: routes.POINTERS},
-    ];
-
-    if (!isAccessibilityOSSettingsVisibilityEnabled) {
-      selectorRouteList.push(
-          {selector: '#ttsSubpageButton', route: routes.MANAGE_TTS_SETTINGS});
-    }
-
-    selectorRouteList.forEach(({selector, route}) => {
-      test(
-          `should focus ${selector} button when returning from ${
-              route.path} subpage`,
-          async () => {
-            initPage();
-            flush();
-            const router = Router.getInstance();
-
-            const subpageButton = page.shadowRoot.querySelector(selector);
-            assertTrue(!!subpageButton);
-
-            subpageButton.click();
-            assertEquals(route, router.getCurrentRoute());
-            assertNotEquals(
-                subpageButton, page.shadowRoot.activeElement,
-                `${selector} should not be focused`);
-
-            const popStateEventPromise = eventToPromise('popstate', window);
-            router.navigateToPreviousRoute();
-            await popStateEventPromise;
-            await waitBeforeNextRender(page);
-
-            assertEquals(routes.MANAGE_ACCESSIBILITY, router.getCurrentRoute());
-            assertEquals(
-                subpageButton, page.shadowRoot.activeElement,
-                `${selector} should be focused`);
-          });
-    });
-  });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
index 65c238e..41ff58e0 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -402,7 +402,6 @@
  [
    'AudioAndCaptionsPage',
    'audio_and_captions_page_tests.js',
-   {enabled: ['features::kAccessibilityOSSettingsVisibility']},
  ],
  ['CellularNetworksList', 'cellular_networks_list_test.js'],
  ['CellularRoamingToggleButton', 'cellular_roaming_toggle_button_test.js'],
@@ -417,13 +416,11 @@
  [
    'CursorAndTouchpadPage',
    'cursor_and_touchpad_page_tests.js',
-   {enabled: ['features::kAccessibilityOSSettingsVisibility']},
  ],
  ['DateTimePage', 'date_time_page_tests.js'],
  [
    'DisplayAndMagnificationPage',
    'display_and_magnification_page_tests.js',
-   {enabled: ['features::kAccessibilityOSSettingsVisibility']},
  ],
  ['EsimInstallErrorDialog', 'esim_install_error_dialog_test.js'],
  ['EsimRemoveProfileDialog', 'esim_remove_profile_dialog_test.js'],
@@ -445,7 +442,6 @@
  [
    'KeyboardAndTextInputPage',
    'keyboard_and_text_input_page_tests.js',
-   {enabled: ['features::kAccessibilityOSSettingsVisibility']},
  ],
  ['KeyboardShortcutBanner', 'keyboard_shortcut_banner_test.js'],
  ['LockScreenPage', 'lock_screen_tests.js'],
@@ -555,7 +551,6 @@
  [
    'TextToSpeechPage',
    'text_to_speech_page_tests.js',
-   {enabled: ['features::kAccessibilityOSSettingsVisibility']},
  ],
  ['TextToSpeechSubpage', 'text_to_speech_subpage_tests.js'],
  ['TimezoneSelector', 'timezone_selector_test.js'],
diff --git a/chrome/test/data/webui/settings/chromeos/text_to_speech_page_tests.js b/chrome/test/data/webui/settings/chromeos/text_to_speech_page_tests.js
index ad4834d88..782fe7b 100644
--- a/chrome/test/data/webui/settings/chromeos/text_to_speech_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/text_to_speech_page_tests.js
@@ -34,8 +34,6 @@
 
   setup(function() {
     PolymerTest.clearBody();
-    loadTimeData.overrideValues(
-      {isAccessibilityOSSettingsVisibilityEnabled: true});
     Router.getInstance().navigateTo(routes.A11Y_TEXT_TO_SPEECH);
   });
 
diff --git a/chrome/test/mini_installer/config/chrome_beta_installed.prop b/chrome/test/mini_installer/config/chrome_beta_installed.prop
index a3b28a10..cb37d10 100644
--- a/chrome/test/mini_installer/config/chrome_beta_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_beta_installed.prop
@@ -41,11 +41,14 @@
           "type": "SZ",
           "data": "$MINI_INSTALLER_FILE_VERSION"
         },
-        "opv": { },
-        "cmd": { }
+        "opv": { }
       },
       "wow_key": "KEY_WOW64_32KEY"
     },
+    "HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY_BETA\\Commands\\rename-chrome-exe": {
+      "exists": "forbidden",
+      "wow_key": "KEY_WOW64_32KEY"
+    },
     "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME_BETA": {
       "exists": "required",
       "values": {
diff --git a/chrome/test/mini_installer/config/chrome_canary_installed.prop b/chrome/test/mini_installer/config/chrome_canary_installed.prop
index 66f58554..45376fa 100644
--- a/chrome/test/mini_installer/config/chrome_canary_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_canary_installed.prop
@@ -41,11 +41,14 @@
           "type": "SZ",
           "data": "$MINI_INSTALLER_FILE_VERSION"
         },
-        "opv": { },
-        "cmd": { }
+        "opv": { }
       },
       "wow_key": "KEY_WOW64_32KEY"
     },
+    "HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY_SXS\\Commands\\rename-chrome-exe": {
+      "exists": "forbidden",
+      "wow_key": "KEY_WOW64_32KEY"
+    },
     "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME_SXS": {
       "exists": "required",
       "values": {
diff --git a/chrome/test/mini_installer/config/chrome_dev_installed.prop b/chrome/test/mini_installer/config/chrome_dev_installed.prop
index 0dcef672..353ff3a 100644
--- a/chrome/test/mini_installer/config/chrome_dev_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_dev_installed.prop
@@ -41,11 +41,14 @@
           "type": "SZ",
           "data": "$MINI_INSTALLER_FILE_VERSION"
         },
-        "opv": { },
-        "cmd": { }
+        "opv": { }
       },
       "wow_key": "KEY_WOW64_32KEY"
     },
+    "HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY_DEV\\Commands\\rename-chrome-exe": {
+      "exists": "forbidden",
+      "wow_key": "KEY_WOW64_32KEY"
+    },
     "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME_DEV": {
       "exists": "required",
       "values": {
diff --git a/chrome/test/mini_installer/config/chrome_system_installed.prop b/chrome/test/mini_installer/config/chrome_system_installed.prop
index 78c4793..e404528c 100644
--- a/chrome/test/mini_installer/config/chrome_system_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_system_installed.prop
@@ -48,11 +48,14 @@
           "type": "SZ",
           "data": "$MINI_INSTALLER_FILE_VERSION"
         },
-        "opv": { },
-        "cmd": { }
+        "opv": { }
       },
       "wow_key": "KEY_WOW64_32KEY"
     },
+    "HKEY_LOCAL_MACHINE\\$CHROME_UPDATE_REGISTRY_SUBKEY\\Commands\\rename-chrome-exe": {
+      "exists": "forbidden",
+      "wow_key": "KEY_WOW64_32KEY"
+    },
     "HKEY_LOCAL_MACHINE\\$CHROME_UPDATE_REGISTRY_SUBKEY\\Commands\\rotate-dtkey": {
       "condition": "'$CHROME_SHORT_NAME' == 'Chrome'",
       "exists": "required",
diff --git a/chrome/test/mini_installer/config/chrome_user_installed.prop b/chrome/test/mini_installer/config/chrome_user_installed.prop
index 4f68e21..9035537 100644
--- a/chrome/test/mini_installer/config/chrome_user_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_user_installed.prop
@@ -40,11 +40,14 @@
           "type": "SZ",
           "data": "$MINI_INSTALLER_FILE_VERSION"
         },
-        "opv": { },
-        "cmd": { }
+        "opv": { }
       },
       "wow_key": "KEY_WOW64_32KEY"
     },
+    "HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY\\Commands\\rename-chrome-exe": {
+      "exists": "forbidden",
+      "wow_key": "KEY_WOW64_32KEY"
+    },
     "HKEY_CURRENT_USER\\$BINARIES_UPDATE_REGISTRY_SUBKEY": {
       "exists": "forbidden",
       "wow_key": "KEY_WOW64_32KEY"
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 758b4a7..bcc2580 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -68,6 +68,8 @@
       "app/app_utils.h",
       "app/app_wake.cc",
       "app/app_wake.h",
+      "app/app_wakeall.cc",
+      "app/app_wakeall.h",
       "auto_run_on_os_upgrade_task.cc",
       "auto_run_on_os_upgrade_task.h",
       "check_for_updates_task.cc",
diff --git a/chrome/updater/app/app_wakeall.cc b/chrome/updater/app/app_wakeall.cc
new file mode 100644
index 0000000..115b3eea3
--- /dev/null
+++ b/chrome/updater/app/app_wakeall.cc
@@ -0,0 +1,88 @@
+// 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/updater/app/app_wakeall.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/launch.h"
+#include "base/task/thread_pool.h"
+#include "base/time/time.h"
+#include "base/version.h"
+#include "chrome/updater/app/app.h"
+#include "chrome/updater/constants.h"
+#include "chrome/updater/util/util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace updater {
+
+// AppWakeAll finds and launches --wake applications for all versions of the
+// updater within the same scope.
+class AppWakeAll : public App {
+ public:
+  AppWakeAll() = default;
+
+ private:
+  ~AppWakeAll() override = default;
+
+  // Overrides for App.
+  void FirstTaskRun() override;
+};
+
+void AppWakeAll::FirstTaskRun() {
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::WithBaseSyncPrimitives()},
+      base::BindOnce(
+          [](UpdaterScope scope) {
+            absl::optional<base::FilePath> base =
+                GetBaseInstallDirectory(scope);
+            if (!base) {
+              return kErrorNoBaseDirectory;
+            }
+            base::FileEnumerator e(*base, false,
+                                   base::FileEnumerator::DIRECTORIES);
+            for (base::FilePath name = e.Next(); !name.empty();
+                 name = e.Next()) {
+              if (!base::Version(name.BaseName().MaybeAsASCII()).IsValid()) {
+                continue;
+              }
+              base::FilePath executable =
+                  name.Append(GetExecutableRelativePath());
+              if (!base::PathExists(executable)) {
+                continue;
+              }
+              base::CommandLine command(executable);
+              command.AppendSwitch(kWakeSwitch);
+              if (scope == UpdaterScope::kSystem) {
+                command.AppendSwitch(kSystemSwitch);
+              }
+              command.AppendSwitch(kEnableLoggingSwitch);
+              command.AppendSwitchASCII(kLoggingModuleSwitch,
+                                        kLoggingModuleSwitchValue);
+              VLOG(1) << "Launching `" << command.GetCommandLineString() << "`";
+              int exit = 0;
+              if (base::LaunchProcess(command, {})
+                      .WaitForExitWithTimeout(base::Minutes(10), &exit)) {
+                VLOG(1) << "`" << command.GetCommandLineString() << "` exited "
+                        << exit;
+              } else {
+                VLOG(1) << "`" << command.GetCommandLineString()
+                        << "` timed out.";
+              }
+            }
+            return kErrorOk;
+          },
+          updater_scope()),
+      base::BindOnce(&AppWakeAll::Shutdown, this));
+}
+
+scoped_refptr<App> MakeAppWakeAll() {
+  return base::MakeRefCounted<AppWakeAll>();
+}
+
+}  // namespace updater
diff --git a/chrome/updater/app/app_wakeall.h b/chrome/updater/app/app_wakeall.h
new file mode 100644
index 0000000..94f7e05
--- /dev/null
+++ b/chrome/updater/app/app_wakeall.h
@@ -0,0 +1,18 @@
+// 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_UPDATER_APP_APP_WAKEALL_H_
+#define CHROME_UPDATER_APP_APP_WAKEALL_H_
+
+#include "base/memory/scoped_refptr.h"
+
+namespace updater {
+
+class App;
+
+scoped_refptr<App> MakeAppWakeAll();
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_APP_APP_WAKEALL_H_
diff --git a/chrome/updater/constants.cc b/chrome/updater/constants.cc
index dcd81f3..57423a2 100644
--- a/chrome/updater/constants.cc
+++ b/chrome/updater/constants.cc
@@ -52,6 +52,7 @@
 const char kAppIdSwitch[] = "app-id";
 const char kAppVersionSwitch[] = "app-version";
 const char kWakeSwitch[] = "wake";
+const char kWakeAllSwitch[] = "wakeall";
 const char kTagSwitch[] = "tag";
 const char kInstallerDataSwitch[] = "installerdata";
 
diff --git a/chrome/updater/constants.h b/chrome/updater/constants.h
index beaa77b8..a91c8f9d 100644
--- a/chrome/updater/constants.h
+++ b/chrome/updater/constants.h
@@ -107,6 +107,9 @@
 // scheduled to invoke the updater periodically.
 extern const char kWakeSwitch[];
 
+// Kicks off the update service for all versions.
+extern const char kWakeAllSwitch[];
+
 // The updater needs to operate in the system context.
 extern const char kSystemSwitch[];
 
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 929eb18..8ddee0a 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -360,7 +360,7 @@
 // Tests the setup and teardown of the fixture.
 TEST_F(IntegrationTest, DoNothing) {}
 
-TEST_F(IntegrationTest, InstallUninstall) {
+TEST_F(IntegrationTest, Install) {
   Install();
   EXPECT_TRUE(WaitForUpdaterExit());
   ExpectInstalled();
@@ -785,7 +785,7 @@
 
 // Tests that installing and uninstalling an old version of the updater from
 // CIPD is possible.
-TEST_F(IntegrationTest, InstallUninstallLowerVersion) {
+TEST_F(IntegrationTest, InstallLowerVersion) {
   ASSERT_NO_FATAL_FAILURE(SetupRealUpdaterLowerVersion());
   ExpectVersionNotActive(kUpdaterVersion);
   Uninstall();
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index a1b6a9e1f..9e31210 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -552,8 +552,8 @@
   for (const base::ProcessEntry& entry : process_entries) {
     VLOG(0) << entry.exe_file() << ", cmdline=" << [](base::ProcessId pid) {
       std::unique_ptr<ProcessInspector> process_inspector =
-          ProcessInspector::Create(
-              base::Process::OpenWithAccess(pid, PROCESS_ALL_ACCESS));
+          ProcessInspector::Create(base::Process::OpenWithAccess(
+              pid, PROCESS_ALL_ACCESS | PROCESS_VM_READ));
       return process_inspector ? process_inspector->command_line() : L"n/a";
     }(entry.pid());
   }
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc
index 1c7f153..f4f3799 100644
--- a/chrome/updater/updater.cc
+++ b/chrome/updater/updater.cc
@@ -26,6 +26,7 @@
 #include "chrome/updater/app/app_uninstall.h"
 #include "chrome/updater/app/app_update.h"
 #include "chrome/updater/app/app_wake.h"
+#include "chrome/updater/app/app_wakeall.h"
 #include "chrome/updater/configurator.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/crash_client.h"
@@ -187,6 +188,10 @@
     return MakeAppWake()->Run();
   }
 
+  if (command_line->HasSwitch(kWakeAllSwitch)) {
+    return MakeAppWakeAll()->Run();
+  }
+
   VLOG(1) << "Unknown command line switch.";
   return kErrorUnknownCommandLine;
 }
@@ -203,8 +208,8 @@
       kTestSwitch,           kUninstallIfUnusedSwitch,
       kUninstallSelfSwitch,  kUninstallSwitch,
       kUpdateSwitch,         kWakeSwitch,
-      kHealthCheckSwitch,    kHandoffSwitch,
-      kRuntimeSwitch,
+      kWakeAllSwitch,        kHealthCheckSwitch,
+      kHandoffSwitch,        kRuntimeSwitch,
   };
   const char** it = base::ranges::find_if(commands, [command_line](auto cmd) {
     return command_line->HasSwitch(cmd);
diff --git a/chromecast/cast_core/runtime/browser/BUILD.gn b/chromecast/cast_core/runtime/browser/BUILD.gn
index 78ee7608..acce93f 100644
--- a/chromecast/cast_core/runtime/browser/BUILD.gn
+++ b/chromecast/cast_core/runtime/browser/BUILD.gn
@@ -91,6 +91,7 @@
     "//components/cast_streaming/browser",
     "//components/cast_streaming/public",
     "//components/media_control/browser",
+    "//components/url_rewrite/browser",
     "//content/public/browser",
     "//mojo/public/cpp/bindings",
     "//third_party/blink/public/common:headers",
@@ -170,10 +171,12 @@
     ":runtime_service_impl",
     "//base",
     "//chromecast/cast_core:cast_core_switches",
+    "//chromecast/common:cors_exempt_headers",
     "//chromecast/media/base:video_plane_controller",
     "//chromecast/metrics:cast_event_builder_simple",
     "//components/url_rewrite/browser",
     "//components/url_rewrite/common",
+    "//content/public/browser",
     "//content/public/common",
     "//media",
   ]
diff --git a/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.cc b/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.cc
index f7327ad..0243f3b 100644
--- a/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.cc
+++ b/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.cc
@@ -13,9 +13,13 @@
 #include "chromecast/cast_core/cast_core_switches.h"
 #include "chromecast/cast_core/runtime/browser/runtime_application_base.h"
 #include "chromecast/cast_core/runtime/browser/runtime_service_impl.h"
+#include "chromecast/common/cors_exempt_headers.h"
 #include "chromecast/media/base/video_plane_controller.h"
 #include "components/cast_receiver/browser/public/application_client.h"
 #include "components/cast_receiver/browser/public/runtime_application.h"
+#include "components/url_rewrite/browser/url_request_rewrite_rules_manager.h"
+#include "components/url_rewrite/common/url_loader_throttle.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/cdm_factory.h"
 
@@ -130,6 +134,32 @@
   application_client_->OnWebContentsCreated(web_contents);
 }
 
+std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
+CastRuntimeContentBrowserClient::CreateURLLoaderThrottles(
+    const network::ResourceRequest& request,
+    content::BrowserContext* browser_context,
+    const base::RepeatingCallback<content::WebContents*()>& wc_getter,
+    content::NavigationUIData* navigation_ui_data,
+    int frame_tree_node_id) {
+  std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles;
+  if (frame_tree_node_id == content::RenderFrameHost::kNoFrameTreeNodeId) {
+    return throttles;
+  }
+
+  content::WebContents* web_contents = wc_getter.Run();
+  if (web_contents) {
+    const auto& rules =
+        application_client_->GetApplicationControls(*web_contents)
+            .GetUrlRequestRewriteRulesManager()
+            .GetCachedRules();
+    if (rules) {
+      throttles.emplace_back(std::make_unique<url_rewrite::URLLoaderThrottle>(
+          rules, base::BindRepeating(&IsCorsExemptHeader)));
+    }
+  }
+  return throttles;
+}
+
 CastRuntimeContentBrowserClient::ApplicationClientObservers::
     ~ApplicationClientObservers() = default;
 
diff --git a/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.h b/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.h
index d948a04..c20fa1d 100644
--- a/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.h
+++ b/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.h
@@ -52,6 +52,13 @@
                                       int child_process_id) override;
   bool IsBufferingEnabled() override;
   void OnWebContentsCreated(content::WebContents* web_contents) override;
+  std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
+  CreateURLLoaderThrottles(
+      const network::ResourceRequest& request,
+      content::BrowserContext* browser_context,
+      const base::RepeatingCallback<content::WebContents*()>& wc_getter,
+      content::NavigationUIData* navigation_ui_data,
+      int frame_tree_node_id) override;
 
  protected:
   void InitializeCoreComponents(CastWebService* web_service);
diff --git a/chromecast/cast_core/runtime/browser/runtime_application_base.cc b/chromecast/cast_core/runtime/browser/runtime_application_base.cc
index 11e5d15..796d7e1a 100644
--- a/chromecast/cast_core/runtime/browser/runtime_application_base.cc
+++ b/chromecast/cast_core/runtime/browser/runtime_application_base.cc
@@ -12,6 +12,7 @@
 #include "chromecast/common/feature_constants.h"
 #include "components/cast_receiver/browser/permissions_manager_impl.h"
 #include "components/media_control/browser/media_blocker.h"
+#include "components/url_rewrite/browser/url_request_rewrite_rules_manager.h"
 #include "content/public/browser/web_contents.h"
 
 namespace chromecast {
@@ -57,10 +58,7 @@
   is_application_running_ = true;
   if (cached_mojom_rules_) {
     // Apply cached URL rewrite rules before anything is done with the page.
-    auto* cast_web_contents = CastWebContents::FromWebContents(
-        embedder_application().GetWebContents());
-    DCHECK(cast_web_contents);
-    cast_web_contents->SetUrlRewriteRules(std::move(cached_mojom_rules_));
+    SetUrlRewriteRules(std::move(cached_mojom_rules_));
   }
 
   LOG(INFO) << "Loaded application: " << *this;
@@ -75,13 +73,11 @@
   std::move(callback).Run(cast_receiver::OkStatus());
 }
 
-cast_receiver::ApplicationClient::ApplicationControls*
+cast_receiver::ApplicationClient::ApplicationControls&
 RuntimeApplicationBase::GetApplicationControls() {
-  if (!embedder_application().GetWebContents()) {
-    return nullptr;
-  }
+  DCHECK(embedder_application().GetWebContents());
 
-  return &application_client_->GetApplicationControls(
+  return application_client_->GetApplicationControls(
       *embedder_application().GetWebContents());
 }
 
@@ -145,10 +141,10 @@
     return;
   }
 
-  auto* cast_web_contents =
-      CastWebContents::FromWebContents(embedder_application().GetWebContents());
-  DCHECK(cast_web_contents);
-  cast_web_contents->SetUrlRewriteRules(std::move(mojom_rules));
+  url_rewrite::UrlRequestRewriteRulesManager&
+      url_request_rewrite_rules_manager =
+          GetApplicationControls().GetUrlRequestRewriteRulesManager();
+  url_request_rewrite_rules_manager.OnRulesUpdated(std::move(mojom_rules));
 }
 
 void RuntimeApplicationBase::SetMediaBlocking(bool load_blocked,
@@ -164,10 +160,8 @@
     return;
   }
 
-  auto* application_controls = GetApplicationControls();
-  DCHECK(application_controls);
   media_control::MediaBlocker& media_blocker =
-      application_controls->GetMediaBlocker();
+      GetApplicationControls().GetMediaBlocker();
 
   media_blocker.BlockMediaLoading(is_media_load_blocked_);
 
diff --git a/chromecast/cast_core/runtime/browser/runtime_application_base.h b/chromecast/cast_core/runtime/browser/runtime_application_base.h
index 7ea5f9a..80560e89 100644
--- a/chromecast/cast_core/runtime/browser/runtime_application_base.h
+++ b/chromecast/cast_core/runtime/browser/runtime_application_base.h
@@ -93,6 +93,12 @@
   // in |app_config_|.
   void SetContentPermissions(content::WebContents& web_contents);
 
+  // Returns the ApplicationControls associated with this application, if such
+  // controls exist.
+  // TODO(crbug.com/1382907): Change to a callback-based API.
+  cast_receiver::ApplicationClient::ApplicationControls&
+  GetApplicationControls();
+
  private:
   void SetWebVisibilityAndPaint(bool is_visible);
 
@@ -100,12 +106,6 @@
   void OnWindowShown() override;
   void OnWindowHidden() override;
 
-  // Returns the ApplicationControls associated with this application, if such
-  // controls exist.
-  // TODO(crbug.com/1382907): Change to a callback-based API.
-  cast_receiver::ApplicationClient::ApplicationControls*
-  GetApplicationControls();
-
   const std::string cast_session_id_;
   const cast_receiver::ApplicationConfig app_config_;
 
diff --git a/chromecast/cast_core/runtime/browser/web_runtime_application.cc b/chromecast/cast_core/runtime/browser/web_runtime_application.cc
index 1798869..59a4ada 100644
--- a/chromecast/cast_core/runtime/browser/web_runtime_application.cc
+++ b/chromecast/cast_core/runtime/browser/web_runtime_application.cc
@@ -73,15 +73,14 @@
 
   DLOG(INFO) << "Inner web contents created";
 
-  CastWebContents* outer_cast_contents =
-      CastWebContents::FromWebContents(embedder_application().GetWebContents());
-  DCHECK(outer_cast_contents);
-
-  SetContentPermissions(*inner_web_contents);
-
-  // TODO(crbug.com/1359571): Decouple URL Rewrite support from CastWebContents.
-  outer_cast_contents->url_rewrite_rules_manager()->AddWebContents(
-      inner_web_contents);
+  auto* outer_web_contents = embedder_application().GetWebContents();
+  if (outer_web_contents) {
+    url_rewrite::UrlRequestRewriteRulesManager&
+        url_request_rewrite_rules_manager =
+            GetApplicationControls().GetUrlRequestRewriteRulesManager();
+    SetContentPermissions(*inner_web_contents);
+    url_request_rewrite_rules_manager.AddWebContents(inner_web_contents);
+  }
 }
 
 void WebRuntimeApplication::MediaStartedPlaying(
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index d843cff0..8a7a8cf 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -1033,8 +1033,8 @@
       <message name="IDS_DIAGNOSTICS_CONNECTIVITY" desc="The label for the connectivity navigation panel item.">
         Connectivity
       </message>
-      <message name="IDS_DIAGNOSTICS_INPUT" desc="The label for the input navigation panel item, which when clicked shows a page offering testers for keyboards, touchpads, and touchscreens.">
-        Input
+      <message name="IDS_DIAGNOSTICS_KEYBOARD" desc="The label for the keyboard navigation panel item, which when clicked shows a page offering testers for keyboards.">
+        Keyboard
       </message>
       <message name="IDS_DIAGNOSTICS_NAME_SERVERS"  desc="Name servers label.">
         {0, plural,
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_INPUT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_INPUT.png.sha1
deleted file mode 100644
index 413de5a..0000000
--- a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_INPUT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6dc2c181abf886bac4f45eba3e5b41946bd40f05
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_KEYBOARD.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_KEYBOARD.png.sha1
new file mode 100644
index 0000000..aa1f7bb
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_KEYBOARD.png.sha1
@@ -0,0 +1 @@
+9d1927537e7a83d58d2a3c7967c405976af3d511
\ No newline at end of file
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
index b8a319b..d11ad68 100644
--- a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
+++ b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
@@ -64,10 +64,9 @@
   new_card_link_clicked_ = false;
   shown_timestamp_ = AutofillClock::Now();
   pending_details_ = CardUnmaskDelegate::UserProvidedUnmaskDetails();
-  card_unmask_challenge_option_ = card_unmask_prompt_options.challenge_option;
+  card_unmask_prompt_options_ = card_unmask_prompt_options;
   card_ = card;
   delegate_ = delegate;
-  reason_ = card_unmask_prompt_options.reason;
   card_unmask_view_ = std::move(card_unmask_view_factory).Run();
   card_unmask_view_->Show();
   unmasking_result_ = AutofillClient::PaymentsRpcResult::kNone;
@@ -91,7 +90,7 @@
         error_message = l10n_util::GetStringFUTF16(
             IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN_SECURITY_CODE,
             GetSideOfCardTranslationString(
-                card_unmask_challenge_option_->cvc_position));
+                card_unmask_prompt_options_.challenge_option->cvc_position));
       } else {
         error_message = l10n_util::GetStringUTF16(
             IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN_CVC);
@@ -224,7 +223,8 @@
 // prompt for local cards should not.
 #if BUILDFLAG(IS_IOS)
   int ids;
-  if (reason_ == AutofillClient::UnmaskCardReason::kAutofill &&
+  if (card_unmask_prompt_options_.reason ==
+          AutofillClient::UnmaskCardReason::kAutofill &&
       ShouldRequestExpirationDate()) {
     ids = card_.record_type() == CreditCard::LOCAL_CARD
               ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_EXPIRED_LOCAL_CARD
@@ -242,14 +242,14 @@
   // If the challenge option is present, return the challenge option instruction
   // information.
   if (IsChallengeOptionPresent()) {
-    DCHECK_EQ(card_unmask_challenge_option_->type,
+    DCHECK_EQ(card_unmask_prompt_options_.challenge_option->type,
               CardUnmaskChallengeOptionType::kCvc);
     return l10n_util::GetStringFUTF16(
         IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_VIRTUAL_CARD,
-        base::NumberToString16(
-            card_unmask_challenge_option_->challenge_input_length),
+        base::NumberToString16(card_unmask_prompt_options_.challenge_option
+                                   ->challenge_input_length),
         GetSideOfCardTranslationString(
-            card_unmask_challenge_option_->cvc_position));
+            card_unmask_prompt_options_.challenge_option->cvc_position));
   }
   return l10n_util::GetStringUTF16(
       card_.record_type() == CreditCard::LOCAL_CARD
@@ -267,7 +267,7 @@
   // case. Rely on the challenge option to inform us whether the
   // CVC is on the front or back of the card.
   if (IsChallengeOptionPresent()) {
-    return card_unmask_challenge_option_->cvc_position ==
+    return card_unmask_prompt_options_.challenge_option->cvc_position ==
                    CvcPosition::kFrontOfCard
                ? IDR_CREDIT_CARD_CVC_HINT_AMEX
                : IDR_CREDIT_CARD_CVC_HINT;
@@ -321,8 +321,9 @@
 
   // Allow three digit American Express Cvc value when it is a back of card cvc
   // challenge option.
-  if (card_unmask_challenge_option_ &&
-      card_unmask_challenge_option_->cvc_position == CvcPosition::kBackOfCard) {
+  if (card_unmask_prompt_options_.challenge_option &&
+      card_unmask_prompt_options_.challenge_option->cvc_position ==
+          CvcPosition::kBackOfCard) {
     return IsValidCreditCardSecurityCode(trimmed_text, card_.network(),
                                          CvcType::kBackOfAmexCvc);
   }
@@ -362,7 +363,8 @@
   // is on the back of the American Express card, we need to handle it
   // separately because its length will be 3.
   if (IsChallengeOptionPresent() && card_.network() == kAmericanExpressCard &&
-      card_unmask_challenge_option_->cvc_position == CvcPosition::kBackOfCard) {
+      card_unmask_prompt_options_.challenge_option->cvc_position ==
+          CvcPosition::kBackOfCard) {
     cvc_type = CvcType::kBackOfAmexCvc;
   } else {
     cvc_type = CvcType::kRegularCvc;
@@ -372,14 +374,15 @@
 }
 
 bool CardUnmaskPromptControllerImpl::IsChallengeOptionPresent() const {
-  return card_unmask_challenge_option_.has_value();
+  return card_unmask_prompt_options_.challenge_option.has_value();
 }
 
 base::TimeDelta CardUnmaskPromptControllerImpl::GetSuccessMessageDuration()
     const {
   return base::Milliseconds(
       card_.record_type() == CreditCard::LOCAL_CARD ||
-              reason_ == AutofillClient::UnmaskCardReason::kPaymentRequest
+              card_unmask_prompt_options_.reason ==
+                  AutofillClient::UnmaskCardReason::kPaymentRequest
           ? 0
           : 500);
 }
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
index ef7396b..734d865 100644
--- a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
+++ b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
@@ -88,11 +88,10 @@
   void LogOnCloseEvents();
   AutofillMetrics::UnmaskPromptEvent GetCloseReasonEvent();
 
-  absl::optional<CardUnmaskChallengeOption> card_unmask_challenge_option_;
+  CardUnmaskPromptOptions card_unmask_prompt_options_;
   raw_ptr<PrefService, DanglingUntriaged> pref_service_;
   bool new_card_link_clicked_ = false;
   CreditCard card_;
-  AutofillClient::UnmaskCardReason reason_;
   base::WeakPtr<CardUnmaskDelegate> delegate_;
   raw_ptr<CardUnmaskPromptView> card_unmask_view_ = nullptr;
 
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_prompt_options.cc b/components/autofill/core/browser/ui/payments/card_unmask_prompt_options.cc
index 98fbce3..9fdb1a5 100644
--- a/components/autofill/core/browser/ui/payments/card_unmask_prompt_options.cc
+++ b/components/autofill/core/browser/ui/payments/card_unmask_prompt_options.cc
@@ -6,6 +6,8 @@
 
 namespace autofill {
 
+CardUnmaskPromptOptions::CardUnmaskPromptOptions() = default;
+
 CardUnmaskPromptOptions::CardUnmaskPromptOptions(
     const absl::optional<CardUnmaskChallengeOption>& challenge_option,
     AutofillClient::UnmaskCardReason reason)
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_prompt_options.h b/components/autofill/core/browser/ui/payments/card_unmask_prompt_options.h
index b5f6fe4..45997c7 100644
--- a/components/autofill/core/browser/ui/payments/card_unmask_prompt_options.h
+++ b/components/autofill/core/browser/ui/payments/card_unmask_prompt_options.h
@@ -15,6 +15,7 @@
 // Holds additional parameters needed to call ShowDialog in the Card Unmask
 // Prompt Controller.
 struct CardUnmaskPromptOptions {
+  CardUnmaskPromptOptions();
   CardUnmaskPromptOptions(
       const absl::optional<CardUnmaskChallengeOption>& challenge_option,
       AutofillClient::UnmaskCardReason reason);
diff --git a/components/browser_ui/styles/android/java/res/values/themes.xml b/components/browser_ui/styles/android/java/res/values/themes.xml
index 8491bc2..8c111e4 100644
--- a/components/browser_ui/styles/android/java/res/values/themes.xml
+++ b/components/browser_ui/styles/android/java/res/values/themes.xml
@@ -56,11 +56,6 @@
     <style name="ThemeOverlay.BrowserUI.DynamicColors" parent="ThemeOverlay.Material3.DynamicColors.DayNight">
         <item name="elevationOverlayColor">?attr/colorPrimary</item>
         <item name="elevationOverlayAccentColor">@android:color/transparent</item>
-    </style>
-    <!-- TODO(skym): Move this into ThemeOverlay.BrowserUI.DynamicColors instead. -->
-    <!-- Applied after the dynamic colors to override the undesired overrides done by the dynamic
-         color overlay, e.g. android:textColorHighlight. -->
-    <style name="ThemeOverlay.DynamicColorOverrides" parent="">
         <!-- android:textColorHighlight applied by Material3 is too dark, so we override it with our
              own color state list to specify a lower alpha. -->
         <item name="android:textColorHighlight">@color/text_highlight_color</item>
@@ -68,13 +63,4 @@
              color state list. -->
         <item name="android:textColorHint">@color/default_text_color_hint_list</item>
     </style>
-    <style name="ThemeOverlay.DynamicButtons" parent="">
-        <item name="globalFilledButtonBgColor">@color/filled_button_bg_dynamic_list</item>
-        <item name="globalFilledButtonTextColor">@color/default_text_color_on_accent1_list</item>
-        <item name="globalTextButtonTextColor">@color/default_text_color_accent1_tint_list</item>
-        <item name="globalTextButtonRippleColor">@color/text_button_ripple_color_list</item>
-        <item name="globalOutlinedButtonBorderColor">@macro/divider_line_bg_color</item>
-        <item name="globalLinkTextColor">?attr/colorPrimary</item>
-        <item name="globalClickableSpanColor">?attr/colorPrimary</item>
-    </style>
 </resources>
diff --git a/components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles/SemanticColorUtils.java b/components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles/SemanticColorUtils.java
index 69119e1..01d507d 100644
--- a/components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles/SemanticColorUtils.java
+++ b/components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles/SemanticColorUtils.java
@@ -8,7 +8,6 @@
 
 import androidx.annotation.AttrRes;
 import androidx.annotation.ColorInt;
-import androidx.annotation.ColorRes;
 import androidx.annotation.DimenRes;
 
 import com.google.android.material.color.MaterialColors;
@@ -19,80 +18,64 @@
  */
 public class SemanticColorUtils {
     private static final String TAG = "SemanticColorUtils";
-    // Temporarily disabled flag because cached features cannot easily be read from components. For
-    // testing changes this can be flipped to true. See https://crrev.com/c/3255853 for context.
-    private static final boolean IS_FULL_DYNAMIC_COLORS = true;
 
-    private static @ColorInt int resolve(
-            @AttrRes int attrRes, @ColorRes int colorRes, Context context) {
-        if (IS_FULL_DYNAMIC_COLORS) {
-            return MaterialColors.getColor(context, attrRes, TAG);
-        } else {
-            return context.getResources().getColor(colorRes);
-        }
+    private static @ColorInt int resolve(@AttrRes int attrRes, Context context) {
+        return MaterialColors.getColor(context, attrRes, TAG);
     }
 
     private static @ColorInt int resolveSurfaceColorElev(
-            @DimenRes int elevationDimen, @ColorRes int colorRes, Context context) {
-        if (IS_FULL_DYNAMIC_COLORS) {
-            return ChromeColors.getSurfaceColor(context, elevationDimen);
-        } else {
-            return context.getResources().getColor(colorRes);
-        }
+            @DimenRes int elevationDimen, Context context) {
+        return ChromeColors.getSurfaceColor(context, elevationDimen);
     }
 
     /** Returns the semantic color value that corresponds to default_bg_color. */
     public static @ColorInt int getDefaultBgColor(Context context) {
-        return resolve(R.attr.colorSurface, R.color.default_bg_color_baseline, context);
+        return resolve(R.attr.colorSurface, context);
     }
 
     /** Returns the semantic color value that corresponds to default_text_color. */
     public static @ColorInt int getDefaultTextColor(Context context) {
-        return resolve(R.attr.colorOnSurface, R.color.default_text_color_baseline, context);
+        return resolve(R.attr.colorOnSurface, context);
     }
 
     /** Returns the semantic color value that corresponds to default_text_color_accent1. */
     public static @ColorInt int getDefaultTextColorAccent1(Context context) {
-        return resolve(R.attr.colorPrimary, R.color.default_text_color_blue_baseline, context);
+        return resolve(R.attr.colorPrimary, context);
     }
 
     /** Returns the semantic color value that corresponds to default_text_color_on_accent1. */
     public static @ColorInt int getDefaultTextColorOnAccent1(Context context) {
-        return resolve(
-                R.attr.colorOnPrimary, R.color.default_text_color_on_accent1_baseline, context);
+        return resolve(R.attr.colorOnPrimary, context);
     }
 
     /** Returns the semantic color value that corresponds to default_text_color_secondary. */
     public static @ColorInt int getDefaultTextColorSecondary(Context context) {
-        return resolve(R.attr.colorOnSurfaceVariant, R.color.default_text_color_secondary_baseline,
-                context);
+        return resolve(R.attr.colorOnSurfaceVariant, context);
     }
 
     /** Returns the semantic color value that corresponds to default_icon_color. */
     public static @ColorInt int getDefaultIconColor(Context context) {
-        return resolve(R.attr.colorOnSurface, R.color.default_icon_color_baseline, context);
+        return resolve(R.attr.colorOnSurface, context);
     }
 
     /** Returns the semantic color value that corresponds to default_icon_color_inverse. */
     public static @ColorInt int getDefaultIconColorInverse(Context context) {
-        return resolve(
-                R.attr.colorOnSurfaceInverse, R.color.default_icon_color_inverse_baseline, context);
+        return resolve(R.attr.colorOnSurfaceInverse, context);
     }
 
     /** Returns the semantic color value that corresponds to default_icon_color_accent1. */
     public static @ColorInt int getDefaultIconColorAccent1(Context context) {
-        return resolve(R.attr.colorPrimary, R.color.default_icon_color_accent1_baseline, context);
+        return resolve(R.attr.colorPrimary, context);
     }
 
     /** Returns the semantic color value that corresponds to default_icon_color_secondary. */
     public static @ColorInt int getDefaultIconColorSecondary(Context context) {
-        return resolve(R.attr.colorOnSurfaceVariant, R.color.default_icon_color_secondary_baseline,
-                context);
+        return resolve(R.attr.colorOnSurfaceVariant, context);
     }
 
     /** Returns the semantic color value that corresponds to divider_line_bg_color. */
     public static @ColorInt int getDividerLineBgColor(Context context) {
-        return resolve(R.attr.colorSurfaceVariant, R.color.divider_line_bg_color_baseline, context);
+        return resolve(R.attr.colorSurfaceVariant, context);
     }
 
     /** Returns the semantic color value that corresponds to bottom_system_nav_color. */
@@ -117,7 +100,7 @@
 
     /** Returns the semantic color value that corresponds to default_control_color_active. */
     public static @ColorInt int getDefaultControlColorActive(Context context) {
-        return resolve(R.attr.colorPrimary, R.color.default_control_color_active_baseline, context);
+        return resolve(R.attr.colorPrimary, context);
     }
 
     /** Returns the semantic color value that corresponds to progress_bar_foreground. */
@@ -132,8 +115,7 @@
 
     /** Returns the semantic color value that corresponds to default_bg_color_elev_2. */
     public static @ColorInt int getDefaultBgColorElev2(Context context) {
-        return resolveSurfaceColorElev(
-                R.dimen.default_elevation_2, R.color.default_bg_color_elev_2_baseline, context);
+        return resolveSurfaceColorElev(R.dimen.default_elevation_2, context);
     }
 
     /** Returns the semantic color value that corresponds to navigation_bubble_background_color. */
@@ -148,23 +130,19 @@
 
     /** Returns the surface color value of the conceptual dialog_bg_color. */
     public static @ColorInt int getDialogBgColor(Context context) {
-        return resolveSurfaceColorElev(
-                R.dimen.dialog_bg_color_elev, R.color.dialog_bg_color_baseline, context);
+        return resolveSurfaceColorElev(R.dimen.dialog_bg_color_elev, context);
     }
 
     /** Returns the surface color value of the conceptual sheet_bg_color. */
     public static @ColorInt int getSheetBgColor(Context context) {
-        return resolveSurfaceColorElev(
-                R.dimen.sheet_bg_color_elev, R.color.sheet_bg_color_baseline, context);
+        return resolveSurfaceColorElev(R.dimen.sheet_bg_color_elev, context);
     }
 
     /** Returns the surface color value of the conceptual snackbar_background_color_baseline. */
     public static @ColorInt int getSnackbarBackgroundColor(Context context) {
-        return resolveSurfaceColorElev(R.dimen.snackbar_background_color_elev,
-                R.color.snackbar_background_color_baseline, context);
+        return resolveSurfaceColorElev(R.dimen.snackbar_background_color_elev, context);
     }
 
-    // Colors that will be experimented with. This is independent of |IS_FULL_DYNAMIC_COLORS|.
     /** Returns the semantic color value that corresponds to default_text_color_link. */
     public static @ColorInt int getDefaultTextColorLink(Context context) {
         final @ColorInt int fallback = context.getColor(R.color.default_text_color_link_baseline);
diff --git a/components/browser_ui/theme/android/java/res/values/themes.xml b/components/browser_ui/theme/android/java/res/values/themes.xml
index 182d1189..77df5cd7 100644
--- a/components/browser_ui/theme/android/java/res/values/themes.xml
+++ b/components/browser_ui/theme/android/java/res/values/themes.xml
@@ -47,15 +47,14 @@
         <item name="elevationOverlayColor">@color/baseline_neutral_600</item>
         <item name="elevationOverlayAccentColor">?attr/colorPrimary</item>
 
-        <!-- Baseline values for the theme attributes in ThemeOverlay.DynamicButtons, used to
-             prevent crashes when the DynamicColorCTAAndroid flag is disabled. -->
-        <item name="globalFilledButtonBgColor">@color/filled_button_bg</item>
-        <item name="globalFilledButtonTextColor">@color/default_text_color_on_accent1_baseline_list</item>
-        <item name="globalTextButtonTextColor">@color/blue_when_enabled_list</item>
-        <item name="globalTextButtonRippleColor">@color/text_button_ripple_color_list_baseline</item>
-        <item name="globalOutlinedButtonBorderColor">@color/divider_line_bg_color_baseline</item>
-        <item name="globalLinkTextColor">@color/default_text_color_link_baseline</item>
-        <item name="globalClickableSpanColor">@color/default_text_color_blue_baseline</item>
+        <!-- Dynamic colors that are applied to the buttons and links. -->
+        <item name="globalFilledButtonBgColor">@color/filled_button_bg_dynamic_list</item>
+        <item name="globalFilledButtonTextColor">@color/default_text_color_on_accent1_list</item>
+        <item name="globalTextButtonTextColor">@color/default_text_color_accent1_tint_list</item>
+        <item name="globalTextButtonRippleColor">@color/text_button_ripple_color_list</item>
+        <item name="globalOutlinedButtonBorderColor">@macro/divider_line_bg_color</item>
+        <item name="globalLinkTextColor">?attr/colorPrimary</item>
+        <item name="globalClickableSpanColor">?attr/colorPrimary</item>
     </style>
     <style name="Base.V31.Theme.BrowserUI" parent="Base.V21.Theme.BrowserUI" />
     <style name="Base.Theme.BrowserUI" parent="Base.V31.Theme.BrowserUI" />
@@ -137,15 +136,14 @@
         <item name="elevationOverlayColor">@color/baseline_neutral_600</item>
         <item name="elevationOverlayAccentColor">?attr/colorPrimary</item>
 
-        <!-- Baseline values for the theme attributes in ThemeOverlay.DynamicButtons, used to
-             prevent crashes when the DynamicColorCTAAndroid flag is disabled. -->
-        <item name="globalFilledButtonBgColor">@color/filled_button_bg</item>
-        <item name="globalFilledButtonTextColor">@color/default_text_color_on_accent1_baseline_list</item>
-        <item name="globalTextButtonTextColor">@color/blue_when_enabled_list</item>
-        <item name="globalTextButtonRippleColor">@color/text_button_ripple_color_list_baseline</item>
-        <item name="globalOutlinedButtonBorderColor">@color/divider_line_bg_color_baseline</item>
-        <item name="globalLinkTextColor">@color/default_text_color_link_baseline</item>
-        <item name="globalClickableSpanColor">@color/default_text_color_blue_baseline</item>
+        <!-- Dynamic colors that are applied to the buttons and links. -->
+        <item name="globalFilledButtonBgColor">@color/filled_button_bg_dynamic_list</item>
+        <item name="globalFilledButtonTextColor">@color/default_text_color_on_accent1_list</item>
+        <item name="globalTextButtonTextColor">@color/default_text_color_accent1_tint_list</item>
+        <item name="globalTextButtonRippleColor">@color/text_button_ripple_color_list</item>
+        <item name="globalOutlinedButtonBorderColor">@macro/divider_line_bg_color</item>
+        <item name="globalLinkTextColor">?attr/colorPrimary</item>
+        <item name="globalClickableSpanColor">?attr/colorPrimary</item>
     </style>
     <!-- Overridden by night mode. -->
     <style name="Theme.BrowserUI.DialogWhenLarge.DayNight" parent="Theme.BrowserUI.DialogWhenLarge"/>
diff --git a/components/cast_receiver/browser/BUILD.gn b/components/cast_receiver/browser/BUILD.gn
index ac48dcb6..acd50fe7 100644
--- a/components/cast_receiver/browser/BUILD.gn
+++ b/components/cast_receiver/browser/BUILD.gn
@@ -10,6 +10,7 @@
     "//components/cast_receiver/common",
     "//components/cast_streaming/browser",
     "//components/media_control/browser",
+    "//components/url_rewrite/browser",
     "//components/url_rewrite/mojom",
     "//content/public/browser",
   ]
diff --git a/components/cast_receiver/browser/DEPS b/components/cast_receiver/browser/DEPS
index c078e2bc..739ac0131 100644
--- a/components/cast_receiver/browser/DEPS
+++ b/components/cast_receiver/browser/DEPS
@@ -4,6 +4,7 @@
   "+components/media_control/browser",
   "+components/on_load_script_injector/browser",
   "+components/url_rewrite/mojom",
+  "+components/url_rewrite/browser",
   "+content/public/browser",
   "+content/public/common",
   "+media",
diff --git a/components/cast_receiver/browser/application_client.cc b/components/cast_receiver/browser/application_client.cc
index 95276e6..48d07bf 100644
--- a/components/cast_receiver/browser/application_client.cc
+++ b/components/cast_receiver/browser/application_client.cc
@@ -6,6 +6,7 @@
 
 #include "base/supports_user_data.h"
 #include "components/media_control/browser/media_blocker.h"
+#include "components/url_rewrite/browser/url_request_rewrite_rules_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -34,15 +35,26 @@
                                 public base::SupportsUserData::Data {
  public:
   explicit ApplicationControlsImpl(content::WebContents& web_contents)
-      : media_blocker_(&web_contents) {}
-  ~ApplicationControlsImpl() override = default;
+      : web_contents_(web_contents), media_blocker_(&web_contents) {
+    url_request_rewrite_rules_manager_.AddWebContents(&web_contents);
+  }
+  ~ApplicationControlsImpl() override {
+    url_request_rewrite_rules_manager_.RemoveWebContents(&*web_contents_);
+  }
 
   media_control::MediaBlocker& GetMediaBlocker() override {
     return media_blocker_;
   }
 
+  url_rewrite::UrlRequestRewriteRulesManager& GetUrlRequestRewriteRulesManager()
+      override {
+    return url_request_rewrite_rules_manager_;
+  }
+
  private:
+  const base::raw_ref<content::WebContents> web_contents_;
   media_control::MediaBlocker media_blocker_;
+  url_rewrite::UrlRequestRewriteRulesManager url_request_rewrite_rules_manager_;
 };
 
 }  // namespace
diff --git a/components/cast_receiver/browser/public/application_client.h b/components/cast_receiver/browser/public/application_client.h
index f7f528f..1c94113 100644
--- a/components/cast_receiver/browser/public/application_client.h
+++ b/components/cast_receiver/browser/public/application_client.h
@@ -31,6 +31,10 @@
 class NetworkContext;
 }  // namespace network::mojom
 
+namespace url_rewrite {
+class UrlRequestRewriteRulesManager;
+}  // namespace url_rewrite
+
 namespace cast_receiver {
 
 class RuntimeApplication;
@@ -52,6 +56,11 @@
 
     // Returns the MediaBlocker instance associated with this application.
     virtual media_control::MediaBlocker& GetMediaBlocker() = 0;
+
+    // Returns the UrlRequestRewriteRulesManager instance associated with this
+    // application.
+    virtual url_rewrite::UrlRequestRewriteRulesManager&
+    GetUrlRequestRewriteRulesManager() = 0;
   };
 
   ApplicationClient();
diff --git a/components/crash/core/browser/resources/crashes.js b/components/crash/core/browser/resources/crashes.js
index d4b9c36..ab7a89c 100644
--- a/components/crash/core/browser/resources/crashes.js
+++ b/components/crash/core/browser/resources/crashes.js
@@ -8,7 +8,8 @@
 
 import 'chrome://resources/js/action_link.js';
 import './strings.m.js';
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+
+import {addWebUiListener} 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';
 
@@ -213,7 +214,7 @@
 }
 
 document.addEventListener('DOMContentLoaded', function() {
-  addWebUIListener('update-crash-list', updateCrashList);
+  addWebUiListener('update-crash-list', updateCrashList);
   $('uploadCrashes').onclick = requestCrashUpload;
   $('showDevDetails').onclick = toggleDevDetails;
   requestCrashes();
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
index 5361b1d..eb2d28e 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -412,6 +412,15 @@
   return Java_WebContentsDelegateAndroid_controlsResizeView(env, obj);
 }
 
+int WebContentsDelegateAndroid::GetVirtualKeyboardHeight(
+    content::WebContents* contents) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
+  if (obj.is_null())
+    return false;
+  return Java_WebContentsDelegateAndroid_getVirtualKeyboardHeight(env, obj);
+}
+
 blink::mojom::DisplayMode WebContentsDelegateAndroid::GetDisplayMode(
     const content::WebContents* web_contents) {
   JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h
index 2b328613..d42e4b7 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.h
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.h
@@ -116,6 +116,7 @@
   bool ShouldAnimateBrowserControlsHeightChanges() override;
   bool DoBrowserControlsShrinkRendererSize(
       content::WebContents* contents) override;
+  int GetVirtualKeyboardHeight(content::WebContents* contents) override;
   blink::mojom::DisplayMode GetDisplayMode(
       const content::WebContents* web_contents) override;
 
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java
index a016799..f9bf9f9 100644
--- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java
+++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java
@@ -184,6 +184,15 @@
     }
 
     /**
+     * @return If shown, returns the height of the virtual keyboard in physical pixels. Otherwise,
+     *         returns 0.
+     */
+    @CalledByNative
+    public int getVirtualKeyboardHeight() {
+        return 0;
+    }
+
+    /**
      * Check and return the {@link DisplayMode} value.
      *
      * @return The {@link DisplayMode} value.
diff --git a/components/endpoint_fetcher/endpoint_fetcher.cc b/components/endpoint_fetcher/endpoint_fetcher.cc
index dba44431..d5e92b5a 100644
--- a/components/endpoint_fetcher/endpoint_fetcher.cc
+++ b/components/endpoint_fetcher/endpoint_fetcher.cc
@@ -201,11 +201,11 @@
   if (base::EqualsCaseInsensitiveASCII(http_method_, "POST")) {
     resource_request->headers.SetHeader(kContentTypeKey, content_type_);
   }
-  DCHECK(headers_.size() % 2 == 0);
+  DCHECK_EQ(headers_.size() % 2, 0UL);
   for (size_t i = 0; i + 1 < headers_.size(); i += 2) {
     resource_request->headers.SetHeader(headers_[i], headers_[i + 1]);
   }
-  DCHECK(cors_exempt_headers_.size() % 2 == 0);
+  DCHECK_EQ(cors_exempt_headers_.size() % 2, 0UL);
   for (size_t i = 0; i + 1 < cors_exempt_headers_.size(); i += 2) {
     resource_request->cors_exempt_headers.SetHeaderIfMissing(
         cors_exempt_headers_[i], cors_exempt_headers_[i + 1]);
@@ -266,6 +266,18 @@
 
   auto response = std::make_unique<EndpointResponse>();
   response->http_status_code = http_status_code;
+  if (http_status_code == net::HTTP_UNAUTHORIZED ||
+      http_status_code == net::HTTP_FORBIDDEN) {
+    response->error_type =
+        absl::make_optional<FetchErrorType>(FetchErrorType::kAuthError);
+    // We cannot assume that the response was in JSON, and hence cannot sanitize
+    // the response. Send the respond as-is.
+    // TODO: Think about how to better handle different MIME-types here.
+    response->response = *response_body;
+    std::move(endpoint_fetcher_callback).Run(std::move(response));
+    return;
+  }
+
   if (net_error_code != net::OK) {
     response->error_type =
         absl::make_optional<FetchErrorType>(FetchErrorType::kNetError);
diff --git a/components/endpoint_fetcher/endpoint_fetcher_unittest.cc b/components/endpoint_fetcher/endpoint_fetcher_unittest.cc
index ccb4acc..bae675fb 100644
--- a/components/endpoint_fetcher/endpoint_fetcher_unittest.cc
+++ b/components/endpoint_fetcher/endpoint_fetcher_unittest.cc
@@ -27,17 +27,19 @@
 const char kContentType[] = "mock_content_type";
 const char kEmail[] = "mock_email@gmail.com";
 const char kEndpoint[] = "https://my-endpoint.com";
+const char kEmptyResponse[] = "";
 const char kExpectedResponse[] = "{}";
 const char kExpectedAuthError[] = "There was an authentication error";
 const char kExpectedResponseError[] = "There was a response error";
 const char kExpectedPrimaryAccountError[] = "No primary accounts found";
 const char kExpectedSanitizationError[] = "There was a sanitization error";
-const char kHttpMethod[] = "POST";
+const char kHttpPostMethod[] = "POST";
 const char kMalformedResponse[] = "asdf";
 const char kMockPostData[] = "mock_post_data";
 int64_t kMockTimeoutMs = 1000000;
 const char kOAuthConsumerName[] = "mock_oauth_consumer_name";
 const char kScope[] = "mock_scope";
+const char kApiKey[] = "api_key";
 }  // namespace
 
 using ::testing::Field;
@@ -45,21 +47,21 @@
 
 class EndpointFetcherTest : public testing::Test {
  protected:
-  EndpointFetcherTest() {}
+  EndpointFetcherTest() = default;
 
   EndpointFetcherTest(const EndpointFetcherTest& endpoint_fetcher_test) =
       delete;
   EndpointFetcherTest& operator=(
       const EndpointFetcherTest& endpoint_fetcher_test) = delete;
 
-  ~EndpointFetcherTest() override {}
+  ~EndpointFetcherTest() override = default;
 
   void SetUp() override {
     scoped_refptr<network::SharedURLLoaderFactory> test_url_loader_factory =
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_);
     endpoint_fetcher_ = std::make_unique<EndpointFetcher>(
-        kOAuthConsumerName, GURL(kEndpoint), kHttpMethod, kContentType,
+        kOAuthConsumerName, GURL(kEndpoint), kHttpPostMethod, kContentType,
         std::vector<std::string>{kScope}, kMockTimeoutMs, kMockPostData,
         TRAFFIC_ANNOTATION_FOR_TESTS, test_url_loader_factory,
         identity_test_env_.identity_manager());
@@ -191,3 +193,18 @@
   endpoint_fetcher()->Fetch(endpoint_fetcher_callback().Get());
   base::RunLoop().RunUntilIdle();
 }
+
+TEST_F(EndpointFetcherTest, PerformRequestAuthError) {
+  SetMockResponse(GURL(kEndpoint), kEmptyResponse, net::HTTP_UNAUTHORIZED,
+                  net::OK);
+  EXPECT_CALL(
+      endpoint_fetcher_callback(),
+      Run(Pointee(AllOf(
+          Field(&EndpointResponse::response, kEmptyResponse),
+          Field(&EndpointResponse::http_status_code, net::HTTP_UNAUTHORIZED),
+          Field(&EndpointResponse::error_type, FetchErrorType::kAuthError)))));
+
+  endpoint_fetcher()->PerformRequest(endpoint_fetcher_callback().Get(),
+                                     kApiKey);
+  base::RunLoop().RunUntilIdle();
+}
diff --git a/components/net_log/resources/net_export.js b/components/net_log/resources/net_export.js
index 671ed4e..0b0556c 100644
--- a/components/net_log/resources/net_export.js
+++ b/components/net_log/resources/net_export.js
@@ -51,7 +51,7 @@
   initialize() {
     // Tell NetExportMessageHandler to notify the UI of future state changes
     // from this point on and listen for net-log-info-changed events.
-    addWebUIListener(
+    addWebUiListener(
         'net-log-info-changed', info => this.onExportNetLogInfoChanged_(info));
     chrome.send('enableNotifyUIWithState');
   }
diff --git a/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc b/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
index 34d0c54..8926824e 100644
--- a/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
+++ b/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
@@ -89,6 +89,62 @@
   const char* observer_name_;
 };
 
+std::string PageLoadMetricsTestWaiter::TimingFieldBitSet::ToDebugString()
+    const {
+  std::string debug_string = "";
+  if (ContainsTimingField(TimingField::kFirstPaint))
+    debug_string += "FirstPaint|";
+
+  if (ContainsTimingField(TimingField::kFirstContentfulPaint))
+    debug_string += "FirstContentfulPaint|";
+
+  if (ContainsTimingField(TimingField::kFirstMeaningfulPaint))
+    debug_string += "FirstMeaningfulPaint|";
+
+  if (ContainsTimingField(TimingField::kFirstPaintAfterBackForwardCacheRestore))
+    debug_string += "FirstPaintAfterBackForwardCacheRestore|";
+
+  if (ContainsTimingField(
+          TimingField::kRequestAnimationFrameAfterBackForwardCacheRestore))
+    debug_string += "RequestAnimationFrameAfterBackForwardCacheRestore|";
+
+  if (ContainsTimingField(TimingField::kDocumentWriteBlockReload))
+    debug_string += "DocumentWriteBlockReload|";
+
+  if (ContainsTimingField(TimingField::kFirstInputDelay))
+    debug_string += "FirstInputDelay|";
+
+  if (ContainsTimingField(TimingField::kFirstInputOrScroll))
+    debug_string += "FirstInputOrScroll|";
+
+  if (ContainsTimingField(
+          TimingField::kFirstInputDelayAfterBackForwardCacheRestore))
+    debug_string += "FirstInputDelayAfterBackForwardCacheRestore|";
+
+  if (ContainsTimingField(TimingField::kLoadTimingInfo))
+    debug_string += "LoadTimingInfo|";
+
+  if (ContainsTimingField(TimingField::kLargestContentfulPaint))
+    debug_string += "LargestContentfulPaint|";
+
+  if (ContainsTimingField(TimingField::kTotalInputDelay))
+    debug_string += "TotalInputDelay|";
+
+  if (ContainsTimingField(TimingField::kFirstContentfulPaint))
+    debug_string += "FirstContentfulPaint|";
+
+  if (ContainsTimingField(TimingField::kLayoutShift))
+    debug_string += "LayoutShift|";
+
+  if (ContainsTimingField(TimingField::kLoadEvent))
+    debug_string += "LoadEvent|";
+
+  if (ContainsTimingField(TimingField::kSoftNavigationCountUpdated))
+    debug_string += "SoftNavigationCountUpdated";
+
+  return debug_string;
+}
+
 PageLoadMetricsTestWaiter::PageLoadMetricsTestWaiter(
     content::WebContents* web_contents)
     : MetricsLifecycleObserver(web_contents),
diff --git a/components/page_load_metrics/browser/page_load_metrics_test_waiter.h b/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
index fdc0fc4..1e9bf8c7a 100644
--- a/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
+++ b/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
@@ -177,6 +177,17 @@
       return !((bitmask_ & other.bitmask_) ^ bitmask_);
     }
 
+    // Returns the string representation of the TimingFields this bitset
+    // contains. This method is not called anywhere and is for debug purpose
+    // only.
+    std::string ToDebugString() const;
+
+    // Returns true if the bitset contains the TimingField. This method is not
+    // called anywhere and is for debug purpose only.
+    bool ContainsTimingField(TimingField time_field) const {
+      return (bitmask_ & static_cast<int>(time_field)) > 0;
+    }
+
    private:
     int bitmask_ = 0;
   };
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index 1269935..3603525 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -191,7 +191,11 @@
 // Controls the ability to import passwords from Chrome's settings page.
 BASE_FEATURE(kPasswordImport,
              "PasswordImport",
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
+             base::FEATURE_ENABLED_BY_DEFAULT);
+#else
              base::FEATURE_DISABLED_BY_DEFAULT);
+#endif
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 BASE_FEATURE(kPasswordManagerRedesign,
diff --git a/components/payments/content/android/payment_app_service_bridge.cc b/components/payments/content/android/payment_app_service_bridge.cc
index 4144de1..f4389b5 100644
--- a/components/payments/content/android/payment_app_service_bridge.cc
+++ b/components/payments/content/android/payment_app_service_bridge.cc
@@ -279,19 +279,6 @@
   return is_off_the_record_;
 }
 
-const std::vector<autofill::AutofillProfile*>&
-PaymentAppServiceBridge::GetBillingProfiles() {
-  // PaymentAppService flow should have short-circuited before this point.
-  NOTREACHED();
-  return dummy_profiles_;
-}
-
-bool PaymentAppServiceBridge::IsRequestedAutofillDataAvailable() {
-  // PaymentAppService flow should have short-circuited before this point.
-  NOTREACHED();
-  return false;
-}
-
 base::WeakPtr<ContentPaymentRequestDelegate>
 PaymentAppServiceBridge::GetPaymentRequestDelegate() const {
   // PaymentAppService flow should have short-circuited before this point.
@@ -319,10 +306,6 @@
   payment_app_created_callback_.Run(std::move(app));
 }
 
-bool PaymentAppServiceBridge::SkipCreatingNativePaymentApps() const {
-  return true;
-}
-
 void PaymentAppServiceBridge::OnPaymentAppCreationError(
     const std::string& error_message,
     AppCreationFailureReason error_reason) {
diff --git a/components/payments/content/android/payment_app_service_bridge.h b/components/payments/content/android/payment_app_service_bridge.h
index 5ba0862e..daedd88 100644
--- a/components/payments/content/android/payment_app_service_bridge.h
+++ b/components/payments/content/android/payment_app_service_bridge.h
@@ -16,10 +16,6 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
-namespace autofill {
-class AutofillProfile;
-}  // namespace autofill
-
 namespace content {
 class RenderFrameHost;
 class WebContents;
@@ -83,8 +79,6 @@
   scoped_refptr<PaymentManifestWebDataService>
   GetPaymentManifestWebDataService() const override;
   bool IsOffTheRecord() const override;
-  const std::vector<autofill::AutofillProfile*>& GetBillingProfiles() override;
-  bool IsRequestedAutofillDataAvailable() override;
   base::WeakPtr<ContentPaymentRequestDelegate> GetPaymentRequestDelegate()
       const override;
   void ShowProcessingSpinner() override;
@@ -94,7 +88,6 @@
   void OnPaymentAppCreationError(
       const std::string& error_message,
       AppCreationFailureReason error_reason) override;
-  bool SkipCreatingNativePaymentApps() const override;
   void OnDoneCreatingPaymentApps() override;
   void SetCanMakePaymentEvenWithoutApps() override;
   base::WeakPtr<CSPChecker> GetCSPChecker() override;
@@ -129,7 +122,6 @@
   scoped_refptr<PaymentManifestWebDataService>
       payment_manifest_web_data_service_;
   bool is_off_the_record_;
-  std::vector<autofill::AutofillProfile*> dummy_profiles_;
   base::WeakPtr<CSPChecker> csp_checker_;
 
   CanMakePaymentCalculatedCallback can_make_payment_calculated_callback_;
diff --git a/components/payments/content/mock_payment_app_factory_delegate.h b/components/payments/content/mock_payment_app_factory_delegate.h
index bb6406d..8156705a 100644
--- a/components/payments/content/mock_payment_app_factory_delegate.h
+++ b/components/payments/content/mock_payment_app_factory_delegate.h
@@ -53,16 +53,12 @@
   }
   MOCK_CONST_METHOD0(GetTwaPackageName, std::string());
   MOCK_METHOD0(ShowProcessingSpinner, void());
-  MOCK_METHOD0(GetBillingProfiles,
-               const std::vector<autofill::AutofillProfile*>&());
-  MOCK_METHOD0(IsRequestedAutofillDataAvailable, bool());
   MOCK_CONST_METHOD0(GetPaymentRequestDelegate,
                      base::WeakPtr<ContentPaymentRequestDelegate>());
   MOCK_METHOD1(OnPaymentAppCreated, void(std::unique_ptr<PaymentApp> app));
   MOCK_METHOD2(OnPaymentAppCreationError,
                void(const std::string& error_message,
                     AppCreationFailureReason reason));
-  MOCK_CONST_METHOD0(SkipCreatingNativePaymentApps, bool());
   MOCK_METHOD0(OnDoneCreatingPaymentApps, void());
   MOCK_METHOD0(SetCanMakePaymentEvenWithoutApps, void());
   MOCK_METHOD0(GetCSPChecker, base::WeakPtr<CSPChecker>());
diff --git a/components/payments/content/payment_app_factory.h b/components/payments/content/payment_app_factory.h
index 656a32d..7ac5c992 100644
--- a/components/payments/content/payment_app_factory.h
+++ b/components/payments/content/payment_app_factory.h
@@ -16,10 +16,6 @@
 
 class GURL;
 
-namespace autofill {
-class AutofillProfile;
-}  // namespace autofill
-
 namespace content {
 class RenderFrameHost;
 class WebContents;
@@ -93,10 +89,6 @@
     // notification.
     virtual void ShowProcessingSpinner() = 0;
 
-    // These parameters are only used to create the autofill payment app.
-    virtual const std::vector<autofill::AutofillProfile*>&
-    GetBillingProfiles() = 0;
-    virtual bool IsRequestedAutofillDataAvailable() = 0;
     virtual base::WeakPtr<ContentPaymentRequestDelegate>
     GetPaymentRequestDelegate() const = 0;
 
@@ -110,12 +102,6 @@
         AppCreationFailureReason failure_reason =
             AppCreationFailureReason::UNKNOWN) = 0;
 
-    // Whether the factory should early exit before creating platform-specific
-    // PaymentApp objects. This is used by PaymentAppServiceBridge to skip
-    // creating native AutofillPaymentApp, which currently cannot be used over
-    // JNI.
-    virtual bool SkipCreatingNativePaymentApps() const = 0;
-
     // Called when all apps of this factory have been created.
     virtual void OnDoneCreatingPaymentApps() = 0;
 
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index f599d41..ab425a7 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -19,7 +19,6 @@
 #include "components/autofill/core/browser/address_normalizer.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/geo/autofill_country.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/validation.h"
@@ -155,15 +154,6 @@
   return GetPaymentRequestDelegate()->GetPaymentManifestWebDataService();
 }
 
-const std::vector<autofill::AutofillProfile*>&
-PaymentRequestState::GetBillingProfiles() {
-  return shipping_profiles_;
-}
-
-bool PaymentRequestState::IsRequestedAutofillDataAvailable() {
-  return is_requested_autofill_data_available_;
-}
-
 bool PaymentRequestState::IsOffTheRecord() const {
   return GetPaymentRequestDelegate()->IsOffTheRecord();
 }
@@ -189,10 +179,6 @@
   get_all_payment_apps_error_reason_ = reason;
 }
 
-bool PaymentRequestState::SkipCreatingNativePaymentApps() const {
-  return false;
-}
-
 void PaymentRequestState::OnDoneCreatingPaymentApps() {
   DCHECK_NE(0U, number_of_payment_app_factories_);
   if (--number_of_payment_app_factories_ > 0U)
@@ -433,13 +419,6 @@
   is_retry_called_ = true;
 }
 
-void PaymentRequestState::AddAutofillPaymentApp(
-    bool selected,
-    const autofill::CreditCard& card) {
-  // TODO(https://crbug.com/1209835): Remove this method.
-  return;
-}
-
 void PaymentRequestState::AddAutofillShippingProfile(
     bool selected,
     const autofill::AutofillProfile& profile) {
@@ -628,7 +607,6 @@
         contact_profiles_.empty()
             ? false
             : profile_comparator()->IsContactInfoComplete(contact_profiles_[0]);
-    is_requested_autofill_data_available_ &= has_complete_contact;
     if (journey_logger_) {
       journey_logger_->SetNumberOfSuggestionsShown(
           JourneyLogger::Section::SECTION_CONTACT_INFO,
@@ -640,8 +618,6 @@
         shipping_profiles_.empty()
             ? false
             : profile_comparator()->IsShippingComplete(shipping_profiles_[0]);
-    is_requested_autofill_data_available_ &= has_complete_shipping;
-
     if (journey_logger_) {
       journey_logger_->SetNumberOfSuggestionsShown(
           JourneyLogger::Section::SECTION_SHIPPING_ADDRESS,
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h
index 863f56a2..d65ddc8 100644
--- a/components/payments/content/payment_request_state.h
+++ b/components/payments/content/payment_request_state.h
@@ -30,7 +30,6 @@
 namespace autofill {
 class AddressNormalizer;
 class AutofillProfile;
-class CreditCard;
 class PersonalDataManager;
 class RegionDataLoader;
 }  // namespace autofill
@@ -138,15 +137,12 @@
       const override;
   scoped_refptr<PaymentManifestWebDataService>
   GetPaymentManifestWebDataService() const override;
-  const std::vector<autofill::AutofillProfile*>& GetBillingProfiles() override;
-  bool IsRequestedAutofillDataAvailable() override;
   bool IsOffTheRecord() const override;
   void OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) override;
   void OnPaymentAppCreationError(
       const std::string& error_message,
       AppCreationFailureReason reason =
           AppCreationFailureReason::UNKNOWN) override;
-  bool SkipCreatingNativePaymentApps() const override;
   void OnDoneCreatingPaymentApps() override;
   void SetCanMakePaymentEvenWithoutApps() override;
   base::WeakPtr<CSPChecker> GetCSPChecker() override;
@@ -233,11 +229,6 @@
     return available_apps_;
   }
 
-  // Creates and adds an AutofillPaymentApp, which makes a copy of |card|.
-  // |selected| indicates if the newly-created app should be selected, after
-  // which observers will be notified.
-  void AddAutofillPaymentApp(bool selected, const autofill::CreditCard& card);
-
   // Creates and adds an AutofillProfile as a shipping profile, which makes a
   // copy of |profile|. |selected| indicates if the newly-created shipping
   // profile should be selected, after which observers will be notified.
@@ -355,11 +346,6 @@
   // complete, valid, and selected.
   bool is_ready_to_pay_ = false;
 
-  // True when the requested autofill data (shipping address and/or contact
-  // information) is complete and valid, even if not selected. This variable is
-  // not affected by payment apps.
-  bool is_requested_autofill_data_available_ = true;
-
   // Whether getting all available apps is finished.
   bool get_all_apps_finished_ = false;
 
@@ -413,7 +399,6 @@
   std::vector<autofill::AutofillProfile*> shipping_profiles_;
   std::vector<autofill::AutofillProfile*> contact_profiles_;
 
-  // Credit cards are directly owned by the apps in this list.
   std::vector<std::unique_ptr<PaymentApp>> available_apps_;
 
   base::WeakPtr<ContentPaymentRequestDelegate> payment_request_delegate_;
diff --git a/components/power_bookmarks/core/BUILD.gn b/components/power_bookmarks/core/BUILD.gn
index 5ad5dfa8..cb20ed7 100644
--- a/components/power_bookmarks/core/BUILD.gn
+++ b/components/power_bookmarks/core/BUILD.gn
@@ -20,6 +20,7 @@
   public_deps = [ ":proto" ]
 
   deps = [
+    ":features",
     ":powers",
     "//base",
     "//base:i18n",
@@ -32,6 +33,15 @@
   ]
 }
 
+static_library("features") {
+  sources = [
+    "power_bookmark_features.cc",
+    "power_bookmark_features.h",
+  ]
+
+  deps = [ "//base" ]
+}
+
 static_library("powers") {
   sources = [
     "powers/power.cc",
@@ -81,6 +91,7 @@
 
   deps = [
     ":core",
+    ":features",
     ":powers",
     "//base/test:test_support",
     "//components/bookmarks/browser",
diff --git a/components/power_bookmarks/core/power_bookmark_features.cc b/components/power_bookmarks/core/power_bookmark_features.cc
new file mode 100644
index 0000000..a2cc053
--- /dev/null
+++ b/components/power_bookmarks/core/power_bookmark_features.cc
@@ -0,0 +1,14 @@
+// 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 "components/power_bookmarks/core/power_bookmark_features.h"
+#include "base/feature_list.h"
+
+namespace power_bookmarks {
+
+BASE_FEATURE(kPowerBookmarkBackend,
+             "PowerBookmarkBackend",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace power_bookmarks
diff --git a/components/power_bookmarks/core/power_bookmark_features.h b/components/power_bookmarks/core/power_bookmark_features.h
new file mode 100644
index 0000000..665b8a0
--- /dev/null
+++ b/components/power_bookmarks/core/power_bookmark_features.h
@@ -0,0 +1,16 @@
+// 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 COMPONENTS_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_FEATURES_H_
+#define COMPONENTS_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace power_bookmarks {
+
+// Controls the power bookmarks backend.
+BASE_DECLARE_FEATURE(kPowerBookmarkBackend);
+
+}  // namespace power_bookmarks
+
+#endif  // COMPONENTS_POWER_BOOKMARKS_CORE_POWER_BOOKMARK_FEATURES_H_
diff --git a/components/power_bookmarks/core/power_bookmark_service.cc b/components/power_bookmarks/core/power_bookmark_service.cc
index fa64ad69..44dd290 100644
--- a/components/power_bookmarks/core/power_bookmark_service.cc
+++ b/components/power_bookmarks/core/power_bookmark_service.cc
@@ -4,9 +4,11 @@
 
 #include "components/power_bookmarks/core/power_bookmark_service.h"
 
+#include "base/feature_list.h"
 #include "base/ranges/algorithm.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/power_bookmarks/core/power_bookmark_data_provider.h"
+#include "components/power_bookmarks/core/power_bookmark_features.h"
 #include "components/power_bookmarks/core/power_bookmark_utils.h"
 #include "components/power_bookmarks/core/powers/power.h"
 #include "components/power_bookmarks/core/powers/power_overview.h"
@@ -28,10 +30,8 @@
 
   backend_ = base::SequenceBound<PowerBookmarkBackend>(backend_task_runner_,
                                                        database_dir);
-  // Features that wish to use the real database, must call
-  // `InitPowerBookmarkDatabase`.
   backend_.AsyncCall(&PowerBookmarkBackend::Init)
-      .WithArgs(/*use_database=*/false);
+      .WithArgs(base::FeatureList::IsEnabled(kPowerBookmarkBackend));
 }
 
 PowerBookmarkService::~PowerBookmarkService() {
@@ -42,11 +42,6 @@
   backend_task_runner_ = nullptr;
 }
 
-void PowerBookmarkService::InitPowerBookmarkDatabase() {
-  backend_.AsyncCall(&PowerBookmarkBackend::Init)
-      .WithArgs(/*use_database=*/true);
-}
-
 void PowerBookmarkService::GetPowersForURL(const GURL& url,
                                            const PowerType& power_type,
                                            PowersCallback callback) {
diff --git a/components/power_bookmarks/core/power_bookmark_service.h b/components/power_bookmarks/core/power_bookmark_service.h
index 6d05dbfd..578e6d7c 100644
--- a/components/power_bookmarks/core/power_bookmark_service.h
+++ b/components/power_bookmarks/core/power_bookmark_service.h
@@ -57,16 +57,6 @@
 
   ~PowerBookmarkService() override;
 
-  // Initializes the power bookmarks backend.
-  // Should only be called in cases where the power is meant to be displayed
-  // to the user. This will also initialize sync for the power bookmarks data
-  // type in cases where another feature hasn't already called this. This
-  // should be called at startup to register the data type with sync as soon
-  // as possible. If this isn't called, then an in-memory database will be
-  // used instead. None of the data will be persisted/synced when using the
-  // in-memory database.
-  void InitPowerBookmarkDatabase();
-
   // Returns a vector of Powers for the given `url` through the given
   // `callback`. Use `power_type` to restrict which type is returned or use
   // POWER_TYPE_UNSPECIFIED to return everything.
diff --git a/components/power_bookmarks/core/power_bookmark_service_unittest.cc b/components/power_bookmarks/core/power_bookmark_service_unittest.cc
index cc9da7d..fab564f8 100644
--- a/components/power_bookmarks/core/power_bookmark_service_unittest.cc
+++ b/components/power_bookmarks/core/power_bookmark_service_unittest.cc
@@ -10,11 +10,13 @@
 #include "base/task/thread_pool.h"
 #include "base/test/bind.h"
 #include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
 #include "components/power_bookmarks/core/power_bookmark_data_provider.h"
+#include "components/power_bookmarks/core/power_bookmark_features.h"
 #include "components/power_bookmarks/core/power_bookmark_service.h"
 #include "components/power_bookmarks/core/powers/power.h"
 #include "components/power_bookmarks/core/powers/power_overview.h"
@@ -49,6 +51,8 @@
 class PowerBookmarkServiceTest : public testing::Test {
  protected:
   void SetUp() override {
+    test_features_.InitAndEnableFeature(kPowerBookmarkBackend);
+
     ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
 
     model_ = bookmarks::TestBookmarkClient::CreateModel();
@@ -58,8 +62,6 @@
     service_ = std::make_unique<PowerBookmarkService>(
         model_.get(), temp_directory_.GetPath(), backend_task_runner_);
     RunUntilIdle();
-
-    service_->InitPowerBookmarkDatabase();
   }
 
   void TearDown() override {
@@ -78,6 +80,8 @@
   bookmarks::BookmarkModel* model() { return model_.get(); }
 
  private:
+  base::test::ScopedFeatureList test_features_;
+
   std::unique_ptr<PowerBookmarkService> service_;
   std::unique_ptr<bookmarks::BookmarkModel> model_;
 
diff --git a/components/privacy_sandbox/privacy_sandbox_settings.cc b/components/privacy_sandbox/privacy_sandbox_settings.cc
index bb91601..c272073 100644
--- a/components/privacy_sandbox/privacy_sandbox_settings.cc
+++ b/components/privacy_sandbox/privacy_sandbox_settings.cc
@@ -95,6 +95,11 @@
 PrivacySandboxSettings::~PrivacySandboxSettings() = default;
 
 bool PrivacySandboxSettings::IsTopicsAllowed() const {
+  // M1 specific
+  if (base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings4)) {
+    return pref_service_->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled);
+  }
+
   // Topics API calculation should be prevented if the user has blocked 3PC
   // cookies, as there will be no context specific check.
   const auto cookie_controls_mode =
@@ -113,6 +118,11 @@
 bool PrivacySandboxSettings::IsTopicsAllowedForContext(
     const GURL& url,
     const absl::optional<url::Origin>& top_frame_origin) const {
+  // M1 specific
+  if (base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings4)) {
+    return IsTopicsAllowed() && IsSiteDataAllowed(url);
+  }
+
   // If the Topics API is disabled completely, it is not available in any
   // context.
   return IsTopicsAllowed() &&
@@ -420,4 +430,15 @@
     observer.OnTopicsDataAccessibleSinceUpdated();
 }
 
+bool PrivacySandboxSettings::IsSiteDataAllowed(const GURL& url) const {
+  // Relying on |host_content_settings_map_| instead of |cookie_settings_|
+  // allows to query whether the site associated with the |url| is allowed to
+  // access Site data (aka ContentSettingsType::COOKIES) from a stand-alone
+  // point of view. This is not possible via |cookies_settings_|, which _also_
+  // takes into account third party context.
+  return host_content_settings_map_->GetContentSetting(
+             url, GURL(), ContentSettingsType::COOKIES) !=
+         ContentSetting::CONTENT_SETTING_BLOCK;
+}
+
 }  // namespace privacy_sandbox
diff --git a/components/privacy_sandbox/privacy_sandbox_settings.h b/components/privacy_sandbox/privacy_sandbox_settings.h
index 8aae2d38..30d7fb6d 100644
--- a/components/privacy_sandbox/privacy_sandbox_settings.h
+++ b/components/privacy_sandbox/privacy_sandbox_settings.h
@@ -220,6 +220,10 @@
   void SetTopicsDataAccessibleFromNow() const;
 
  private:
+  // Whether the site associated with the URL is allowed to access site data or
+  // not, as a primary context.
+  bool IsSiteDataAllowed(const GURL& url) const;
+
   base::ObserverList<Observer>::Unchecked observers_;
 
   std::unique_ptr<Delegate> delegate_;
diff --git a/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc b/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc
index d0b1f58..e54835a 100644
--- a/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc
+++ b/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc
@@ -25,7 +25,7 @@
 
 using Topic = browsing_topics::Topic;
 
-class PrivacySandboxSettingsTest : public testing::Test {
+class PrivacySandboxSettingsTest : public testing::TestWithParam<bool> {
  public:
   PrivacySandboxSettingsTest()
       : browser_task_environment_(
@@ -960,4 +960,138 @@
   EXPECT_TRUE(privacy_sandbox_settings()->IsPrivacySandboxEnabled());
 }
 
+/**
+ * A test fixture for privacy sandbox M1 for Topics.
+ */
+class PrivacySandboxSettingsTopicsM1Test : public PrivacySandboxSettingsTest {
+ public:
+  void InitializeFeaturesBeforeStart() override {
+    feature_list_.InitWithFeatureState(
+        privacy_sandbox::kPrivacySandboxSettings4, GetParam());
+  }
+
+  void InitializePrefsBeforeStart() override {
+    prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, GetParam());
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(PrivacySandboxSettingsTestM1Instance,
+                         PrivacySandboxSettingsTopicsM1Test,
+                         testing::Bool());
+
+TEST_P(PrivacySandboxSettingsTopicsM1Test, IsTopicsAllowed_M1) {
+  bool is_topics_pref_enabled =
+      prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled);
+  EXPECT_EQ(is_topics_pref_enabled,
+            privacy_sandbox_settings()->IsTopicsAllowed());
+
+  // Update the underlying topics prefs to disable.
+  prefs()->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, false);
+  // Topics should always be disabled is the underlying pref is disabled.
+  EXPECT_FALSE(privacy_sandbox_settings()->IsTopicsAllowed());
+}
+
+// Test that CookieControlsMode has not affect on whether Topics is allowed or
+// not.
+TEST_P(PrivacySandboxSettingsTopicsM1Test,
+       IsTopicAllowed_CookieControlsMode_M1) {
+  bool is_topics_pref_enabled =
+      prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled);
+
+  prefs()->SetUserPref(
+      prefs::kCookieControlsMode,
+      base::Value(static_cast<int>(
+          content_settings::CookieControlsMode::kBlockThirdParty)));
+  EXPECT_EQ(is_topics_pref_enabled,
+            privacy_sandbox_settings()->IsTopicsAllowed());
+
+  prefs()->SetUserPref(prefs::kCookieControlsMode,
+                       base::Value(static_cast<int>(
+                           content_settings::CookieControlsMode::kOff)));
+  EXPECT_EQ(is_topics_pref_enabled,
+            privacy_sandbox_settings()->IsTopicsAllowed());
+}
+
+// Test that the Topics API is blocked for a site if its corresponding Site data
+// setting is blocked, regardless if the default content setting is allowed.
+TEST_P(PrivacySandboxSettingsTopicsM1Test,
+       IsTopicAllowedForContext_CookieContentSetting_PrimaryPattern_Block_M1) {
+  bool is_topics_pref_enabled =
+      prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled);
+  EXPECT_EQ(is_topics_pref_enabled,
+            privacy_sandbox_settings()->IsTopicsAllowed());
+
+  // Allow default cookie content setting but block on primary pattern.
+  privacy_sandbox_test_util::SetupMinimialTestStateForM1(
+      prefs(), host_content_settings_map(),
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "*", ContentSetting::CONTENT_SETTING_BLOCK}});
+  EXPECT_FALSE(privacy_sandbox_settings()->IsTopicsAllowedForContext(
+      GURL("https://embedded.com"), {}));
+}
+
+// Test that the Topics API is allowed for a site if its corresponding Site data
+// setting is allowed, regardless if the default content setting is blocked.
+TEST_P(PrivacySandboxSettingsTopicsM1Test,
+       IsTopicAllowedForContext_CookieContentSetting_PrimaryPattern_Allow_M1) {
+  bool is_topics_pref_enabled =
+      prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled);
+  bool is_topics_allowed = privacy_sandbox_settings()->IsTopicsAllowed();
+  EXPECT_EQ(is_topics_pref_enabled,
+            privacy_sandbox_settings()->IsTopicsAllowed());
+
+  // Block default cookie content setting but allow on primary pattern.
+  privacy_sandbox_test_util::SetupMinimialTestStateForM1(
+      prefs(), host_content_settings_map(),
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+      /*user_cookie_exceptions=*/
+      {{"https://embedded.com", "*", ContentSetting::CONTENT_SETTING_ALLOW}});
+
+  // Should allow topics for the context, as long as the low level Topics API is
+  // allowed.
+  EXPECT_EQ(is_topics_allowed,
+            privacy_sandbox_settings()->IsTopicsAllowedForContext(
+                GURL("https://embedded.com"), {}));
+}
+
+// Test that the Topics API is allowed by default for any site without any
+// corresponding Site data exception.
+TEST_P(PrivacySandboxSettingsTopicsM1Test,
+       IsTopicAllowedForContext_CookieContentSetting_Default_Allow_M1) {
+  bool is_topics_pref_enabled =
+      prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled);
+  bool is_topics_allowed = privacy_sandbox_settings()->IsTopicsAllowed();
+  EXPECT_EQ(is_topics_pref_enabled,
+            privacy_sandbox_settings()->IsTopicsAllowed());
+
+  // Allow default cookie content setting.
+  privacy_sandbox_test_util::SetupMinimialTestStateForM1(
+      prefs(), host_content_settings_map(),
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+      /*user_cookie_exceptions=*/{});
+
+  // Should allow topics for the context, as long as the low level Topics API is
+  // allowed.
+  EXPECT_EQ(is_topics_allowed,
+            privacy_sandbox_settings()->IsTopicsAllowedForContext(
+                GURL("https://embedded.com"), {}));
+}
+
+// Test that the Topics API is blocked by default for any site without any
+// corresponding Site data exception.
+TEST_P(PrivacySandboxSettingsTopicsM1Test,
+       IsTopicAllowedForContext_CookieContentSetting_Default_Block_M1) {
+  EXPECT_EQ(prefs()->GetBoolean(prefs::kPrivacySandboxM1TopicsEnabled),
+            privacy_sandbox_settings()->IsTopicsAllowed());
+
+  // Block default cookie content setting.
+  privacy_sandbox_test_util::SetupMinimialTestStateForM1(
+      prefs(), host_content_settings_map(),
+      /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+      /*user_cookie_exceptions=*/{});
+  EXPECT_FALSE(privacy_sandbox_settings()->IsTopicsAllowedForContext(
+      GURL("https://embedded.com"), {}));
+}
+
 }  // namespace privacy_sandbox
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util.cc b/components/privacy_sandbox/privacy_sandbox_test_util.cc
index d640b5c6..8f2c624 100644
--- a/components/privacy_sandbox/privacy_sandbox_test_util.cc
+++ b/components/privacy_sandbox/privacy_sandbox_test_util.cc
@@ -23,6 +23,31 @@
 MockPrivacySandboxSettingsDelegate::~MockPrivacySandboxSettingsDelegate() =
     default;
 
+void SetupMinimialTestStateForM1(
+    sync_preferences::TestingPrefServiceSyncable* testing_pref_service,
+    HostContentSettingsMap* map,
+    ContentSetting default_cookie_setting,
+    const std::vector<CookieContentSettingException>& user_cookie_exceptions) {
+  // Setup cookie content settings.
+  auto user_provider = std::make_unique<content_settings::MockProvider>();
+
+  if (default_cookie_setting != kNoSetting) {
+    user_provider->SetWebsiteSetting(
+        ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
+        ContentSettingsType::COOKIES, base::Value(default_cookie_setting));
+  }
+
+  for (const auto& exception : user_cookie_exceptions) {
+    user_provider->SetWebsiteSetting(
+        ContentSettingsPattern::FromString(exception.primary_pattern),
+        ContentSettingsPattern::FromString(exception.secondary_pattern),
+        ContentSettingsType::COOKIES, base::Value(exception.content_setting));
+  }
+
+  content_settings::TestUtils::OverrideProvider(
+      map, std::move(user_provider), HostContentSettingsMap::DEFAULT_PROVIDER);
+}
+
 void SetupTestState(
     sync_preferences::TestingPrefServiceSyncable* testing_pref_service,
     HostContentSettingsMap* map,
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util.h b/components/privacy_sandbox/privacy_sandbox_test_util.h
index 5befb7f..107e5660 100644
--- a/components/privacy_sandbox/privacy_sandbox_test_util.h
+++ b/components/privacy_sandbox/privacy_sandbox_test_util.h
@@ -52,6 +52,14 @@
   ContentSetting content_setting;
 };
 
+// Sets up non-managed cookie preferences and content settings based on provided
+// parameters.
+void SetupMinimialTestStateForM1(
+    sync_preferences::TestingPrefServiceSyncable* testing_pref_service,
+    HostContentSettingsMap* map,
+    ContentSetting default_cookie_setting,
+    const std::vector<CookieContentSettingException>& user_cookie_exceptions);
+
 // Sets up preferences and content settings based on provided parameters.
 void SetupTestState(
     sync_preferences::TestingPrefServiceSyncable* testing_pref_service,
diff --git a/components/reading_list/core/BUILD.gn b/components/reading_list/core/BUILD.gn
index d8cd96cc..2709b9e 100644
--- a/components/reading_list/core/BUILD.gn
+++ b/components/reading_list/core/BUILD.gn
@@ -18,9 +18,9 @@
     "reading_list_model_storage.h",
     "reading_list_pref_names.cc",
     "reading_list_pref_names.h",
-    "reading_list_store.cc",
-    "reading_list_store.h",
-    "reading_list_store_delegate.h",
+    "reading_list_sync_bridge.cc",
+    "reading_list_sync_bridge.h",
+    "reading_list_sync_bridge_delegate.h",
   ]
   deps = [
     "//base",
@@ -40,7 +40,7 @@
     "offline_url_utils_unittest.cc",
     "reading_list_entry_unittest.cc",
     "reading_list_model_unittest.cc",
-    "reading_list_store_unittest.cc",
+    "reading_list_sync_bridge_unittest.cc",
   ]
   deps = [
     ":core",
diff --git a/components/reading_list/core/reading_list_entry.cc b/components/reading_list/core/reading_list_entry.cc
index 4e1c34aa..9b492bc 100644
--- a/components/reading_list/core/reading_list_entry.cc
+++ b/components/reading_list/core/reading_list_entry.cc
@@ -13,7 +13,7 @@
 #include "base/time/time.h"
 #include "components/reading_list/core/offline_url_utils.h"
 #include "components/reading_list/core/proto/reading_list.pb.h"
-#include "components/reading_list/core/reading_list_store.h"
+#include "components/reading_list/core/reading_list_sync_bridge.h"
 #include "components/sync/protocol/reading_list_specifics.pb.h"
 #include "net/base/backoff_entry_serializer.h"
 
@@ -568,8 +568,9 @@
 #if !defined(NDEBUG)
   std::unique_ptr<sync_pb::ReadingListSpecifics> new_this_pb(
       AsReadingListSpecifics());
-  DCHECK(ReadingListStore::CompareEntriesForSync(*old_this_pb, *new_this_pb));
-  DCHECK(ReadingListStore::CompareEntriesForSync(*other_pb, *new_this_pb));
+  DCHECK(
+      ReadingListSyncBridge::CompareEntriesForSync(*old_this_pb, *new_this_pb));
+  DCHECK(ReadingListSyncBridge::CompareEntriesForSync(*other_pb, *new_this_pb));
 #endif
 }
 
diff --git a/components/reading_list/core/reading_list_entry.h b/components/reading_list/core/reading_list_entry.h
index a68412e..bf3146c 100644
--- a/components/reading_list/core/reading_list_entry.h
+++ b/components/reading_list/core/reading_list_entry.h
@@ -158,14 +158,16 @@
   // Merge |this| and |other| into this.
   // Local fields are kept from |this|.
   // Each field is merged individually keeping the highest value as defined by
-  // the |ReadingListStore.CompareEntriesForSync| function.
+  // the |ReadingListSyncBridge.CompareEntriesForSync| function.
   //
   // After calling |MergeLocalStateFrom|, the result must verify
-  // ReadingListStore.CompareEntriesForSync(old_this.AsReadingListSpecifics(),
-  //                                        new_this.AsReadingListSpecifics())
+  // ReadingListSyncBridge::CompareEntriesForSync(
+  //     old_this.AsReadingListSpecifics(),
+  //     new_this.AsReadingListSpecifics())
   // and
-  // ReadingListStore.CompareEntriesForSync(other.AsReadingListSpecifics(),
-  //                                        new_this.AsReadingListSpecifics()).
+  // ReadingListSyncBridge::CompareEntriesForSync(
+  //     other.AsReadingListSpecifics(),
+  //     new_this.AsReadingListSpecifics()).
   void MergeWithEntry(const ReadingListEntry& other);
 
   ReadingListEntry& operator=(ReadingListEntry&& other);
diff --git a/components/reading_list/core/reading_list_entry_unittest.cc b/components/reading_list/core/reading_list_entry_unittest.cc
index 437c3854..95af484 100644
--- a/components/reading_list/core/reading_list_entry_unittest.cc
+++ b/components/reading_list/core/reading_list_entry_unittest.cc
@@ -406,7 +406,7 @@
 
 // Tests the merging of two ReadingListEntry.
 // Additional merging tests are done in
-// ReadingListStoreTest.CompareEntriesForSync
+// ReadingListSyncBridgeTest.CompareEntriesForSync
 TEST(ReadingListEntry, MergeWithEntry) {
   ReadingListEntry local_entry(GURL("http://example.com/"), "title",
                                base::Time::FromTimeT(10));
diff --git a/components/reading_list/core/reading_list_model_impl.h b/components/reading_list/core/reading_list_model_impl.h
index 78487eb..b19d5468 100644
--- a/components/reading_list/core/reading_list_model_impl.h
+++ b/components/reading_list/core/reading_list_model_impl.h
@@ -12,7 +12,7 @@
 #include "components/reading_list/core/reading_list_entry.h"
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/reading_list/core/reading_list_model_storage.h"
-#include "components/reading_list/core/reading_list_store_delegate.h"
+#include "components/reading_list/core/reading_list_sync_bridge_delegate.h"
 
 namespace base {
 class Clock;
@@ -22,7 +22,7 @@
 
 // Concrete implementation of a reading list model using in memory lists.
 class ReadingListModelImpl : public ReadingListModel,
-                             public ReadingListStoreDelegate {
+                             public ReadingListSyncBridgeDelegate {
  public:
   using ReadingListEntries = std::map<GURL, ReadingListEntry>;
 
diff --git a/components/reading_list/core/reading_list_model_storage.h b/components/reading_list/core/reading_list_model_storage.h
index 315b776..5b3fd1c 100644
--- a/components/reading_list/core/reading_list_model_storage.h
+++ b/components/reading_list/core/reading_list_model_storage.h
@@ -10,7 +10,7 @@
 #include "components/reading_list/core/reading_list_entry.h"
 
 class ReadingListModel;
-class ReadingListStoreDelegate;
+class ReadingListSyncBridgeDelegate;
 
 namespace base {
 class Clock;
@@ -37,8 +37,10 @@
   // This will trigger store initalization and load persistent entries.
   // Pass the |clock| from the |model| to ensure synchroization when loading
   // entries. Must be called no more than once.
+  // TODO(crbug.com/1386158): ReadingListSyncBridgeDelegate shouldn't belong in
+  // this interface.
   virtual void SetReadingListModel(ReadingListModel* model,
-                                   ReadingListStoreDelegate* delegate,
+                                   ReadingListSyncBridgeDelegate* delegate,
                                    base::Clock* clock) = 0;
 
   // Starts a transaction. All Save/Remove entry will be delayed until the
diff --git a/components/reading_list/core/reading_list_model_unittest.cc b/components/reading_list/core/reading_list_model_unittest.cc
index 9426e506..bb26a27 100644
--- a/components/reading_list/core/reading_list_model_unittest.cc
+++ b/components/reading_list/core/reading_list_model_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/test/simple_test_clock.h"
 #include "components/reading_list/core/reading_list_model_impl.h"
 #include "components/reading_list/core/reading_list_model_storage.h"
-#include "components/reading_list/core/reading_list_store_delegate.h"
+#include "components/reading_list/core/reading_list_sync_bridge_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -29,7 +29,7 @@
  public:
   TestReadingListStorage(TestReadingListStorageObserver* observer,
                          base::SimpleTestClock* clock)
-      : entries_(new ReadingListStoreDelegate::ReadingListEntries()),
+      : entries_(new ReadingListSyncBridgeDelegate::ReadingListEntries()),
         observer_(observer),
         clock_(clock) {}
 
@@ -76,7 +76,7 @@
   }
 
   void SetReadingListModel(ReadingListModel* model,
-                           ReadingListStoreDelegate* delegate,
+                           ReadingListSyncBridgeDelegate* delegate,
                            base::Clock* clock) override {
     delegate->StoreLoaded(std::move(entries_));
     clock_ = static_cast<base::SimpleTestClock*>(clock);
@@ -104,7 +104,7 @@
   }
 
  private:
-  std::unique_ptr<ReadingListStoreDelegate::ReadingListEntries> entries_;
+  std::unique_ptr<ReadingListSyncBridgeDelegate::ReadingListEntries> entries_;
   raw_ptr<TestReadingListStorageObserver> observer_;
   raw_ptr<base::SimpleTestClock> clock_;
 };
diff --git a/components/reading_list/core/reading_list_store.cc b/components/reading_list/core/reading_list_sync_bridge.cc
similarity index 87%
rename from components/reading_list/core/reading_list_store.cc
rename to components/reading_list/core/reading_list_sync_bridge.cc
index 556a35d..a6939f4 100644
--- a/components/reading_list/core/reading_list_store.cc
+++ b/components/reading_list/core/reading_list_sync_bridge.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/reading_list/core/reading_list_store.h"
+#include "components/reading_list/core/reading_list_sync_bridge.h"
 
 #include <set>
 #include <utility>
@@ -19,46 +19,48 @@
 #include "components/sync/model/mutable_data_batch.h"
 #include "components/sync/protocol/model_type_state.pb.h"
 
-ReadingListStore::ReadingListStore(
+ReadingListSyncBridge::ReadingListSyncBridge(
     syncer::OnceModelTypeStoreFactory create_store_callback,
     std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
     : ModelTypeSyncBridge(std::move(change_processor)),
       create_store_callback_(std::move(create_store_callback)),
       pending_transaction_count_(0) {}
 
-ReadingListStore::~ReadingListStore() {
+ReadingListSyncBridge::~ReadingListSyncBridge() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(0, pending_transaction_count_);
 }
 
-void ReadingListStore::SetReadingListModel(ReadingListModel* model,
-                                           ReadingListStoreDelegate* delegate,
-                                           base::Clock* clock) {
+void ReadingListSyncBridge::SetReadingListModel(
+    ReadingListModel* model,
+    ReadingListSyncBridgeDelegate* delegate,
+    base::Clock* clock) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   model_ = model;
   delegate_ = delegate;
   clock_ = clock;
   std::move(create_store_callback_)
       .Run(syncer::READING_LIST,
-           base::BindOnce(&ReadingListStore::OnStoreCreated,
+           base::BindOnce(&ReadingListSyncBridge::OnStoreCreated,
                           weak_ptr_factory_.GetWeakPtr()));
 }
 
 std::unique_ptr<ReadingListModelStorage::ScopedBatchUpdate>
-ReadingListStore::EnsureBatchCreated() {
+ReadingListSyncBridge::EnsureBatchCreated() {
   return std::make_unique<ScopedBatchUpdate>(this);
 }
 
-ReadingListStore::ScopedBatchUpdate::ScopedBatchUpdate(ReadingListStore* store)
+ReadingListSyncBridge::ScopedBatchUpdate::ScopedBatchUpdate(
+    ReadingListSyncBridge* store)
     : store_(store) {
   store_->BeginTransaction();
 }
 
-ReadingListStore::ScopedBatchUpdate::~ScopedBatchUpdate() {
+ReadingListSyncBridge::ScopedBatchUpdate::~ScopedBatchUpdate() {
   store_->CommitTransaction();
 }
 
-void ReadingListStore::BeginTransaction() {
+void ReadingListSyncBridge::BeginTransaction() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   pending_transaction_count_++;
   if (pending_transaction_count_ == 1) {
@@ -66,18 +68,19 @@
   }
 }
 
-void ReadingListStore::CommitTransaction() {
+void ReadingListSyncBridge::CommitTransaction() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   pending_transaction_count_--;
   if (pending_transaction_count_ == 0) {
-    store_->CommitWriteBatch(std::move(batch_),
-                             base::BindOnce(&ReadingListStore::OnDatabaseSave,
-                                            weak_ptr_factory_.GetWeakPtr()));
+    store_->CommitWriteBatch(
+        std::move(batch_),
+        base::BindOnce(&ReadingListSyncBridge::OnDatabaseSave,
+                       weak_ptr_factory_.GetWeakPtr()));
     batch_.reset();
   }
 }
 
-void ReadingListStore::SaveEntry(const ReadingListEntry& entry) {
+void ReadingListSyncBridge::SaveEntry(const ReadingListEntry& entry) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto token = EnsureBatchCreated();
 
@@ -100,7 +103,7 @@
                           batch_->GetMetadataChangeList());
 }
 
-void ReadingListStore::RemoveEntry(const ReadingListEntry& entry) {
+void ReadingListSyncBridge::RemoveEntry(const ReadingListEntry& entry) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto token = EnsureBatchCreated();
 
@@ -112,11 +115,11 @@
                              batch_->GetMetadataChangeList());
 }
 
-syncer::ModelTypeSyncBridge* ReadingListStore::GetModelTypeSyncBridge() {
+syncer::ModelTypeSyncBridge* ReadingListSyncBridge::GetModelTypeSyncBridge() {
   return this;
 }
 
-void ReadingListStore::OnDatabaseLoad(
+void ReadingListSyncBridge::OnDatabaseLoad(
     const absl::optional<syncer::ModelError>& error,
     std::unique_ptr<syncer::ModelTypeStore::RecordList> entries) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -125,7 +128,7 @@
     return;
   }
   auto loaded_entries =
-      std::make_unique<ReadingListStoreDelegate::ReadingListEntries>();
+      std::make_unique<ReadingListSyncBridgeDelegate::ReadingListEntries>();
 
   for (const syncer::ModelTypeStore::Record& r : *entries) {
     reading_list::ReadingListLocal proto;
@@ -147,11 +150,12 @@
 
   delegate_->StoreLoaded(std::move(loaded_entries));
 
-  store_->ReadAllMetadata(base::BindOnce(&ReadingListStore::OnReadAllMetadata,
-                                         weak_ptr_factory_.GetWeakPtr()));
+  store_->ReadAllMetadata(
+      base::BindOnce(&ReadingListSyncBridge::OnReadAllMetadata,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
-void ReadingListStore::OnReadAllMetadata(
+void ReadingListSyncBridge::OnReadAllMetadata(
     const absl::optional<syncer::ModelError>& error,
     std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -162,12 +166,12 @@
   }
 }
 
-void ReadingListStore::OnDatabaseSave(
+void ReadingListSyncBridge::OnDatabaseSave(
     const absl::optional<syncer::ModelError>& error) {
   return;
 }
 
-void ReadingListStore::OnStoreCreated(
+void ReadingListSyncBridge::OnStoreCreated(
     const absl::optional<syncer::ModelError>& error,
     std::unique_ptr<syncer::ModelTypeStore> store) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -176,7 +180,7 @@
     return;
   }
   store_ = std::move(store);
-  store_->ReadAllData(base::BindOnce(&ReadingListStore::OnDatabaseLoad,
+  store_->ReadAllData(base::BindOnce(&ReadingListSyncBridge::OnDatabaseLoad,
                                      weak_ptr_factory_.GetWeakPtr()));
   return;
 }
@@ -184,7 +188,7 @@
 // Creates an object used to communicate changes in the sync metadata to the
 // model type store.
 std::unique_ptr<syncer::MetadataChangeList>
-ReadingListStore::CreateMetadataChangeList() {
+ReadingListSyncBridge::CreateMetadataChangeList() {
   return syncer::ModelTypeStore::WriteBatch::CreateMetadataChangeList();
 }
 
@@ -200,7 +204,7 @@
 // Durable storage writes, if not able to combine all change atomically, should
 // save the metadata after the data changes, so that this merge will be re-
 // driven by sync if is not completely saved during the current run.
-absl::optional<syncer::ModelError> ReadingListStore::MergeSyncData(
+absl::optional<syncer::ModelError> ReadingListSyncBridge::MergeSyncData(
     std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
     syncer::EntityChangeList entity_changes) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -289,7 +293,7 @@
 // |metadata_change_list| in case when some of the data changes are filtered
 // out, or even be empty in case when a commit confirmation is processed and
 // only the metadata needs to persisted.
-absl::optional<syncer::ModelError> ReadingListStore::ApplySyncChanges(
+absl::optional<syncer::ModelError> ReadingListSyncBridge::ApplySyncChanges(
     std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
     syncer::EntityChangeList entity_changes) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -345,8 +349,8 @@
   return {};
 }
 
-void ReadingListStore::GetData(StorageKeyList storage_keys,
-                               DataCallback callback) {
+void ReadingListSyncBridge::GetData(StorageKeyList storage_keys,
+                                    DataCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto batch = std::make_unique<syncer::MutableDataBatch>();
   for (const std::string& url_string : storage_keys) {
@@ -359,7 +363,7 @@
   std::move(callback).Run(std::move(batch));
 }
 
-void ReadingListStore::GetAllDataForDebugging(DataCallback callback) {
+void ReadingListSyncBridge::GetAllDataForDebugging(DataCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto batch = std::make_unique<syncer::MutableDataBatch>();
 
@@ -371,8 +375,8 @@
   std::move(callback).Run(std::move(batch));
 }
 
-void ReadingListStore::AddEntryToBatch(syncer::MutableDataBatch* batch,
-                                       const ReadingListEntry& entry) {
+void ReadingListSyncBridge::AddEntryToBatch(syncer::MutableDataBatch* batch,
+                                            const ReadingListEntry& entry) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   std::unique_ptr<sync_pb::ReadingListSpecifics> entry_pb =
       entry.AsReadingListSpecifics();
@@ -391,7 +395,7 @@
 // it is also used to verify the hash of remote data. If a data type was never
 // launched pre-USS, then method does not need to be different from
 // GetStorageKey().
-std::string ReadingListStore::GetClientTag(
+std::string ReadingListSyncBridge::GetClientTag(
     const syncer::EntityData& entity_data) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return GetStorageKey(entity_data);
@@ -403,13 +407,13 @@
 // Theoretically this function doesn't need to be stable across multiple calls
 // on the same or different clients, but to keep things simple, it probably
 // should be.
-std::string ReadingListStore::GetStorageKey(
+std::string ReadingListSyncBridge::GetStorageKey(
     const syncer::EntityData& entity_data) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return entity_data.specifics.reading_list().entry_id();
 }
 
-bool ReadingListStore::CompareEntriesForSync(
+bool ReadingListSyncBridge::CompareEntriesForSync(
     const sync_pb::ReadingListSpecifics& lhs,
     const sync_pb::ReadingListSpecifics& rhs) {
   DCHECK(lhs.entry_id() == rhs.entry_id());
diff --git a/components/reading_list/core/reading_list_store.h b/components/reading_list/core/reading_list_sync_bridge.h
similarity index 88%
rename from components/reading_list/core/reading_list_store.h
rename to components/reading_list/core/reading_list_sync_bridge.h
index 26c78fd..d4998036 100644
--- a/components/reading_list/core/reading_list_store.h
+++ b/components/reading_list/core/reading_list_sync_bridge.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_H_
-#define COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_SYNC_BRIDGE_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_SYNC_BRIDGE_H_
 
 #include <memory>
 #include <string>
@@ -12,7 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "components/reading_list/core/reading_list_model_storage.h"
-#include "components/reading_list/core/reading_list_store_delegate.h"
+#include "components/reading_list/core/reading_list_sync_bridge_delegate.h"
 #include "components/sync/model/model_error.h"
 #include "components/sync/model/model_type_store.h"
 #include "components/sync/model/model_type_sync_bridge.h"
@@ -25,23 +25,23 @@
 class ReadingListModel;
 
 // A ReadingListModelStorage storing and syncing data in protobufs.
-class ReadingListStore : public ReadingListModelStorage,
-                         public syncer::ModelTypeSyncBridge {
+class ReadingListSyncBridge : public ReadingListModelStorage,
+                              public syncer::ModelTypeSyncBridge {
  public:
-  ReadingListStore(
+  ReadingListSyncBridge(
       syncer::OnceModelTypeStoreFactory create_store_callback,
       std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
 
-  ReadingListStore(const ReadingListStore&) = delete;
-  ReadingListStore& operator=(const ReadingListStore&) = delete;
+  ReadingListSyncBridge(const ReadingListSyncBridge&) = delete;
+  ReadingListSyncBridge& operator=(const ReadingListSyncBridge&) = delete;
 
-  ~ReadingListStore() override;
+  ~ReadingListSyncBridge() override;
 
   std::unique_ptr<ScopedBatchUpdate> EnsureBatchCreated() override;
 
   // ReadingListModelStorage implementation
   void SetReadingListModel(ReadingListModel* model,
-                           ReadingListStoreDelegate* delegate,
+                           ReadingListSyncBridgeDelegate* delegate,
                            base::Clock* clock) override;
 
   void SaveEntry(const ReadingListEntry& entry) override;
@@ -141,7 +141,7 @@
 
   class ScopedBatchUpdate : public ReadingListModelStorage::ScopedBatchUpdate {
    public:
-    explicit ScopedBatchUpdate(ReadingListStore* store);
+    explicit ScopedBatchUpdate(ReadingListSyncBridge* store);
 
     ScopedBatchUpdate(const ScopedBatchUpdate&) = delete;
     ScopedBatchUpdate& operator=(const ScopedBatchUpdate&) = delete;
@@ -149,7 +149,7 @@
     ~ScopedBatchUpdate() override;
 
    private:
-    raw_ptr<ReadingListStore> store_;
+    raw_ptr<ReadingListSyncBridge> store_;
   };
 
  private:
@@ -168,7 +168,7 @@
 
   std::unique_ptr<syncer::ModelTypeStore> store_;
   raw_ptr<ReadingListModel> model_;
-  raw_ptr<ReadingListStoreDelegate> delegate_;
+  raw_ptr<ReadingListSyncBridgeDelegate> delegate_;
   syncer::OnceModelTypeStoreFactory create_store_callback_;
 
   int pending_transaction_count_;
@@ -178,7 +178,7 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
-  base::WeakPtrFactory<ReadingListStore> weak_ptr_factory_{this};
+  base::WeakPtrFactory<ReadingListSyncBridge> weak_ptr_factory_{this};
 };
 
-#endif  // COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_H_
+#endif  // COMPONENTS_READING_LIST_CORE_READING_LIST_SYNC_BRIDGE_H_
diff --git a/components/reading_list/core/reading_list_store_delegate.h b/components/reading_list/core/reading_list_sync_bridge_delegate.h
similarity index 62%
rename from components/reading_list/core/reading_list_store_delegate.h
rename to components/reading_list/core/reading_list_sync_bridge_delegate.h
index 0155be9..d464038 100644
--- a/components/reading_list/core/reading_list_store_delegate.h
+++ b/components/reading_list/core/reading_list_sync_bridge_delegate.h
@@ -2,22 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_DELEGATE_H_
-#define COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_DELEGATE_H_
+#ifndef COMPONENTS_READING_LIST_CORE_READING_LIST_SYNC_BRIDGE_DELEGATE_H_
+#define COMPONENTS_READING_LIST_CORE_READING_LIST_SYNC_BRIDGE_DELEGATE_H_
 
 #include <map>
 
 class ReadingListEntry;
 
-// The delegate to handle callbacks from the ReadingListStore.
-class ReadingListStoreDelegate {
+// The delegate to handle callbacks from the ReadingListSyncBridge.
+class ReadingListSyncBridgeDelegate {
  public:
   using ReadingListEntries = std::map<GURL, ReadingListEntry>;
 
-  ReadingListStoreDelegate(const ReadingListStoreDelegate&) = delete;
-  ReadingListStoreDelegate& operator=(const ReadingListStoreDelegate&) = delete;
+  ReadingListSyncBridgeDelegate(const ReadingListSyncBridgeDelegate&) = delete;
+  ReadingListSyncBridgeDelegate& operator=(
+      const ReadingListSyncBridgeDelegate&) = delete;
 
-  // These three methods handle callbacks from a ReadingListStore.
+  // These three methods handle callbacks from a ReadingListSyncBridge.
   // This method is called when the local store is loaded. |entries| contains
   // the ReadingListEntry present on the device before sync starts.
   virtual void StoreLoaded(std::unique_ptr<ReadingListEntries> entries) = 0;
@@ -37,8 +38,8 @@
   virtual void SyncRemoveEntry(const GURL& url) = 0;
 
  protected:
-  ReadingListStoreDelegate() {}
-  virtual ~ReadingListStoreDelegate() {}
+  ReadingListSyncBridgeDelegate() {}
+  virtual ~ReadingListSyncBridgeDelegate() {}
 };
 
-#endif  // COMPONENTS_READING_LIST_CORE_READING_LIST_STORE_DELEGATE_H_
+#endif  // COMPONENTS_READING_LIST_CORE_READING_LIST_SYNC_BRIDGE_DELEGATE_H_
diff --git a/components/reading_list/core/reading_list_store_unittest.cc b/components/reading_list/core/reading_list_sync_bridge_unittest.cc
similarity index 85%
rename from components/reading_list/core/reading_list_store_unittest.cc
rename to components/reading_list/core/reading_list_sync_bridge_unittest.cc
index a7590ec..b57f7c0 100644
--- a/components/reading_list/core/reading_list_store_unittest.cc
+++ b/components/reading_list/core/reading_list_sync_bridge_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/reading_list/core/reading_list_store.h"
+#include "components/reading_list/core/reading_list_sync_bridge.h"
 
 #include <map>
 #include <set>
@@ -49,7 +49,8 @@
 void ExpectAB(const sync_pb::ReadingListSpecifics& entryA,
               const sync_pb::ReadingListSpecifics& entryB,
               bool possible) {
-  EXPECT_EQ(ReadingListStore::CompareEntriesForSync(entryA, entryB), possible);
+  EXPECT_EQ(ReadingListSyncBridge::CompareEntriesForSync(entryA, entryB),
+            possible);
   std::unique_ptr<ReadingListEntry> a =
       ReadingListEntry::FromReadingListSpecifics(entryA,
                                                  base::Time::FromTimeT(10));
@@ -65,8 +66,10 @@
   } else {
     // If transition is not possible, the transition shold be possible to the
     // merged state.
-    EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryA, *mergedEntry));
-    EXPECT_TRUE(ReadingListStore::CompareEntriesForSync(entryB, *mergedEntry));
+    EXPECT_TRUE(
+        ReadingListSyncBridge::CompareEntriesForSync(entryA, *mergedEntry));
+    EXPECT_TRUE(
+        ReadingListSyncBridge::CompareEntriesForSync(entryB, *mergedEntry));
   }
 }
 
@@ -87,19 +90,19 @@
                       syncer::MetadataChangeList* metadata_change_list) = 0;
 };
 
-class ReadingListStoreTest : public testing::Test,
-                             public ReadingListStoreDelegate {
+class ReadingListSyncBridgeTest : public testing::Test,
+                                  public ReadingListSyncBridgeDelegate {
  protected:
-  ReadingListStoreTest()
+  ReadingListSyncBridgeTest()
       : store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()) {
     ON_CALL(processor_, IsTrackingMetadata())
         .WillByDefault(testing::Return(true));
     ClearState();
-    reading_list_store_ = std::make_unique<ReadingListStore>(
+    reading_list_sync_bridge_ = std::make_unique<ReadingListSyncBridge>(
         syncer::ModelTypeStoreTestUtil::MoveStoreToFactory(std::move(store_)),
         processor_.CreateForwardingProcessor());
     model_ = std::make_unique<ReadingListModelImpl>(nullptr, nullptr, &clock_);
-    reading_list_store_->SetReadingListModel(model_.get(), this, &clock_);
+    reading_list_sync_bridge_->SetReadingListModel(model_.get(), this, &clock_);
 
     base::RunLoop().RunUntilIdle();
   }
@@ -121,7 +124,7 @@
     sync_merged_.clear();
   }
 
-  // These three mathods handle callbacks from a ReadingListStore.
+  // These three mathods handle callbacks from a ReadingListSyncBridge.
   void StoreLoaded(std::unique_ptr<ReadingListEntries> entries) override {}
 
   // Handle sync events.
@@ -149,7 +152,7 @@
   std::unique_ptr<syncer::ModelTypeStore> store_;
   std::unique_ptr<ReadingListModelImpl> model_;
   base::SimpleTestClock clock_;
-  std::unique_ptr<ReadingListStore> reading_list_store_;
+  std::unique_ptr<ReadingListSyncBridge> reading_list_sync_bridge_;
 
   int sync_add_called_;
   int sync_remove_called_;
@@ -159,11 +162,11 @@
   std::map<std::string, bool> sync_merged_;
 };
 
-TEST_F(ReadingListStoreTest, CheckEmpties) {
+TEST_F(ReadingListSyncBridgeTest, CheckEmpties) {
   EXPECT_EQ(0ul, model_->size());
 }
 
-TEST_F(ReadingListStoreTest, SaveOneRead) {
+TEST_F(ReadingListSyncBridgeTest, SaveOneRead) {
   ReadingListEntry entry(GURL("http://read.example.com/"), "read title",
                          AdvanceAndGetTime(&clock_));
   entry.SetRead(true, AdvanceAndGetTime(&clock_));
@@ -173,11 +176,11 @@
                   MatchesSpecifics("read title", "http://read.example.com/",
                                    sync_pb::ReadingListSpecifics::READ),
                   _));
-  reading_list_store_->SaveEntry(entry);
+  reading_list_sync_bridge_->SaveEntry(entry);
   AssertCounts(0, 0, 0);
 }
 
-TEST_F(ReadingListStoreTest, SaveOneUnread) {
+TEST_F(ReadingListSyncBridgeTest, SaveOneUnread) {
   ReadingListEntry entry(GURL("http://unread.example.com/"), "unread title",
                          AdvanceAndGetTime(&clock_));
   EXPECT_CALL(processor_,
@@ -185,11 +188,11 @@
                   MatchesSpecifics("unread title", "http://unread.example.com/",
                                    sync_pb::ReadingListSpecifics::UNSEEN),
                   _));
-  reading_list_store_->SaveEntry(entry);
+  reading_list_sync_bridge_->SaveEntry(entry);
   AssertCounts(0, 0, 0);
 }
 
-TEST_F(ReadingListStoreTest, SyncMergeOneEntry) {
+TEST_F(ReadingListSyncBridgeTest, SyncMergeOneEntry) {
   EXPECT_CALL(processor_, Put(_, _, _)).Times(0);
 
   syncer::EntityChangeList remote_input;
@@ -206,16 +209,16 @@
       "http://read.example.com/", std::move(data)));
 
   std::unique_ptr<syncer::MetadataChangeList> metadata_changes(
-      reading_list_store_->CreateMetadataChangeList());
-  auto error = reading_list_store_->MergeSyncData(std::move(metadata_changes),
-                                                  std::move(remote_input));
+      reading_list_sync_bridge_->CreateMetadataChangeList());
+  auto error = reading_list_sync_bridge_->MergeSyncData(
+      std::move(metadata_changes), std::move(remote_input));
   AssertCounts(1, 0, 0);
   EXPECT_EQ(sync_added_.size(), 1u);
   EXPECT_EQ(sync_added_.count("http://read.example.com/"), 1u);
   EXPECT_EQ(sync_added_["http://read.example.com/"], true);
 }
 
-TEST_F(ReadingListStoreTest, ApplySyncChangesOneAdd) {
+TEST_F(ReadingListSyncBridgeTest, ApplySyncChangesOneAdd) {
   EXPECT_CALL(processor_, Put(_, _, _)).Times(0);
 
   ReadingListEntry entry(GURL("http://read.example.com/"), "read title",
@@ -230,15 +233,16 @@
 
   add_changes.push_back(syncer::EntityChange::CreateAdd(
       "http://read.example.com/", std::move(data)));
-  auto error = reading_list_store_->ApplySyncChanges(
-      reading_list_store_->CreateMetadataChangeList(), std::move(add_changes));
+  auto error = reading_list_sync_bridge_->ApplySyncChanges(
+      reading_list_sync_bridge_->CreateMetadataChangeList(),
+      std::move(add_changes));
   AssertCounts(1, 0, 0);
   EXPECT_EQ(sync_added_.size(), 1u);
   EXPECT_EQ(sync_added_.count("http://read.example.com/"), 1u);
   EXPECT_EQ(sync_added_["http://read.example.com/"], true);
 }
 
-TEST_F(ReadingListStoreTest, ApplySyncChangesOneMerge) {
+TEST_F(ReadingListSyncBridgeTest, ApplySyncChangesOneMerge) {
   AdvanceAndGetTime(&clock_);
   model_->AddEntry(GURL("http://unread.example.com/"), "unread title",
                    reading_list::ADDED_VIA_CURRENT_APP);
@@ -258,15 +262,16 @@
   syncer::EntityChangeList add_changes;
   add_changes.push_back(syncer::EntityChange::CreateAdd(
       "http://unread.example.com/", std::move(data)));
-  auto error = reading_list_store_->ApplySyncChanges(
-      reading_list_store_->CreateMetadataChangeList(), std::move(add_changes));
+  auto error = reading_list_sync_bridge_->ApplySyncChanges(
+      reading_list_sync_bridge_->CreateMetadataChangeList(),
+      std::move(add_changes));
   AssertCounts(0, 0, 1);
   EXPECT_EQ(sync_merged_.size(), 1u);
   EXPECT_EQ(sync_merged_.count("http://unread.example.com/"), 1u);
   EXPECT_EQ(sync_merged_["http://unread.example.com/"], true);
 }
 
-TEST_F(ReadingListStoreTest, ApplySyncChangesOneIgnored) {
+TEST_F(ReadingListSyncBridgeTest, ApplySyncChangesOneIgnored) {
   // Read entry but with unread URL as it must update the other one.
   ReadingListEntry old_entry(GURL("http://unread.example.com/"),
                              "old unread title", AdvanceAndGetTime(&clock_));
@@ -289,25 +294,26 @@
   syncer::EntityChangeList add_changes;
   add_changes.push_back(syncer::EntityChange::CreateAdd(
       "http://unread.example.com/", std::move(data)));
-  auto error = reading_list_store_->ApplySyncChanges(
-      reading_list_store_->CreateMetadataChangeList(), std::move(add_changes));
+  auto error = reading_list_sync_bridge_->ApplySyncChanges(
+      reading_list_sync_bridge_->CreateMetadataChangeList(),
+      std::move(add_changes));
   AssertCounts(0, 0, 1);
   EXPECT_EQ(sync_merged_.size(), 1u);
 }
 
-TEST_F(ReadingListStoreTest, ApplySyncChangesOneRemove) {
+TEST_F(ReadingListSyncBridgeTest, ApplySyncChangesOneRemove) {
   syncer::EntityChangeList delete_changes;
   delete_changes.push_back(
       syncer::EntityChange::CreateDelete("http://read.example.com/"));
-  auto error = reading_list_store_->ApplySyncChanges(
-      reading_list_store_->CreateMetadataChangeList(),
+  auto error = reading_list_sync_bridge_->ApplySyncChanges(
+      reading_list_sync_bridge_->CreateMetadataChangeList(),
       std::move(delete_changes));
   AssertCounts(0, 1, 0);
   EXPECT_EQ(sync_removed_.size(), 1u);
   EXPECT_EQ(sync_removed_.count("http://read.example.com/"), 1u);
 }
 
-TEST_F(ReadingListStoreTest, CompareEntriesForSync) {
+TEST_F(ReadingListSyncBridgeTest, CompareEntriesForSync) {
   sync_pb::ReadingListSpecifics entryA;
   sync_pb::ReadingListSpecifics entryB;
   entryA.set_entry_id("http://foo.bar/");
@@ -336,8 +342,8 @@
 
   // You cannot change the URL of an entry.
   entryA.set_url("http://foo.foo/");
-  EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryA, entryB));
-  EXPECT_FALSE(ReadingListStore::CompareEntriesForSync(entryB, entryA));
+  EXPECT_FALSE(ReadingListSyncBridge::CompareEntriesForSync(entryA, entryB));
+  EXPECT_FALSE(ReadingListSyncBridge::CompareEntriesForSync(entryB, entryA));
   entryA.set_url("http://foo.bar/");
 
   // You can set a title to a title later in alphabetical order if the
diff --git a/components/session_proto_db/session_proto_storage.h b/components/session_proto_db/session_proto_storage.h
index a0fcd840..b514a58 100644
--- a/components/session_proto_db/session_proto_storage.h
+++ b/components/session_proto_db/session_proto_storage.h
@@ -19,7 +19,11 @@
  public:
   using KeyAndValue = std::pair<std::string, T>;
 
-  // Callback which is used when content is acquired.
+  // Callback which is used when content is acquired. Users are recommended to
+  // check the bool value which indicates whether the operation has succeeded,
+  // because when the operation fails, the callback could be posted to the
+  // thread pool to execute instead of the original thread, which might lead to
+  // use-after-free.
   using LoadCallback = base::OnceCallback<void(bool, std::vector<KeyAndValue>)>;
 
   // Used for confirming an operation was completed successfully (e.g.
diff --git a/components/signin/public/base/signin_switches.cc b/components/signin/public/base/signin_switches.cc
index 751f91c9..4fc1d78 100644
--- a/components/signin/public/base/signin_switches.cc
+++ b/components/signin/public/base/signin_switches.cc
@@ -58,7 +58,7 @@
 #if BUILDFLAG(IS_IOS)
 BASE_FEATURE(kEnableCbdSignOut,
              "EnableCbdSignOut",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 #endif
 
 // This feature disables all extended sync promos.
diff --git a/components/system_media_controls/win/system_media_controls_win.cc b/components/system_media_controls/win/system_media_controls_win.cc
index c3532a1b..9291a58c 100644
--- a/components/system_media_controls/win/system_media_controls_win.cc
+++ b/components/system_media_controls/win/system_media_controls_win.cc
@@ -30,8 +30,12 @@
 
 namespace internal {
 
+using ABI::Windows::Media::IPlaybackPositionChangeRequestedEventArgs;
 using ABI::Windows::Media::ISystemMediaTransportControls;
+using ABI::Windows::Media::ISystemMediaTransportControls2;
 using ABI::Windows::Media::ISystemMediaTransportControlsButtonPressedEventArgs;
+using ABI::Windows::Media::ISystemMediaTransportControlsTimelineProperties;
+using ABI::Windows::Media::PlaybackPositionChangeRequestedEventArgs;
 using ABI::Windows::Media::SystemMediaTransportControls;
 using ABI::Windows::Media::SystemMediaTransportControlsButton;
 using ABI::Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs;
@@ -56,9 +60,19 @@
 }
 
 SystemMediaControlsWin::~SystemMediaControlsWin() {
-  if (has_valid_registration_token_) {
+  if (has_valid_button_pressed_registration_token_) {
     DCHECK(system_media_controls_);
-    system_media_controls_->remove_ButtonPressed(registration_token_);
+    system_media_controls_->remove_ButtonPressed(
+        button_pressed_registration_token_);
+    if (has_valid_playback_position_change_requested_registration_token_) {
+      Microsoft::WRL::ComPtr<ISystemMediaTransportControls2>
+          system_media_controls_2;
+      HRESULT hr = system_media_controls_.As(&system_media_controls_2);
+      if (SUCCEEDED(hr)) {
+        system_media_controls_2->remove_PlaybackPositionChangeRequested(
+            playback_position_change_requested_registration_token_);
+      }
+    }
     ClearMetadata();
   }
 
@@ -89,17 +103,17 @@
   if (FAILED(hr))
     return false;
 
-  auto handler =
+  auto button_pressed_handler =
       Microsoft::WRL::Callback<ABI::Windows::Foundation::ITypedEventHandler<
           SystemMediaTransportControls*,
           SystemMediaTransportControlsButtonPressedEventArgs*>>(
           &SystemMediaControlsWin::ButtonPressed);
-  hr = system_media_controls_->add_ButtonPressed(handler.Get(),
-                                                 &registration_token_);
+  hr = system_media_controls_->add_ButtonPressed(
+      button_pressed_handler.Get(), &button_pressed_registration_token_);
   if (FAILED(hr))
     return false;
 
-  has_valid_registration_token_ = true;
+  has_valid_button_pressed_registration_token_ = true;
 
   hr = system_media_controls_->put_IsEnabled(true);
   if (FAILED(hr))
@@ -172,6 +186,36 @@
   DCHECK(SUCCEEDED(hr));
 }
 
+void SystemMediaControlsWin::SetIsSeekToEnabled(bool value) {
+  DCHECK(initialized_);
+
+  Microsoft::WRL::ComPtr<ISystemMediaTransportControls2>
+      system_media_controls_2;
+  HRESULT hr = system_media_controls_.As(&system_media_controls_2);
+  if (FAILED(hr))
+    return;
+
+  if (value) {
+    auto playback_position_change_requested_handler =
+        Microsoft::WRL::Callback<ABI::Windows::Foundation::ITypedEventHandler<
+            SystemMediaTransportControls*,
+            PlaybackPositionChangeRequestedEventArgs*>>(
+            &SystemMediaControlsWin::PlaybackPositionChangeRequested);
+    hr = system_media_controls_2->add_PlaybackPositionChangeRequested(
+        playback_position_change_requested_handler.Get(),
+        &playback_position_change_requested_registration_token_);
+    DCHECK(SUCCEEDED(hr));
+    has_valid_playback_position_change_requested_registration_token_ = true;
+  } else {
+    if (has_valid_playback_position_change_requested_registration_token_) {
+      hr = system_media_controls_2->remove_PlaybackPositionChangeRequested(
+          playback_position_change_requested_registration_token_);
+      DCHECK(SUCCEEDED(hr));
+      has_valid_playback_position_change_requested_registration_token_ = false;
+    }
+  }
+}
+
 void SystemMediaControlsWin::SetPlaybackStatus(PlaybackStatus status) {
   DCHECK(initialized_);
   HRESULT hr =
@@ -275,6 +319,52 @@
   DCHECK(SUCCEEDED(hr));
 }
 
+void SystemMediaControlsWin::SetPosition(
+    const media_session::MediaPosition& position) {
+  DCHECK(initialized_);
+
+  Microsoft::WRL::ComPtr<ISystemMediaTransportControls2>
+      system_media_controls_2;
+  HRESULT hr = system_media_controls_.As(&system_media_controls_2);
+  if (FAILED(hr))
+    return;
+
+  Microsoft::WRL::ComPtr<ISystemMediaTransportControlsTimelineProperties>
+      timeline_properties;
+  base::win::ScopedHString id = base::win::ScopedHString::Create(
+      RuntimeClass_Windows_Media_SystemMediaTransportControlsTimelineProperties);
+  hr = base::win::RoActivateInstance(id.get(), &timeline_properties);
+  DCHECK(SUCCEEDED(hr));
+
+  ABI::Windows::Foundation::TimeSpan timeSpanZero = {0};
+
+  hr = timeline_properties->put_MinSeekTime(timeSpanZero);
+  DCHECK(SUCCEEDED(hr));
+
+  hr = timeline_properties->put_StartTime(timeSpanZero);
+  DCHECK(SUCCEEDED(hr));
+
+  hr = timeline_properties->put_Position(
+      position.GetPosition().ToWinrtTimeSpan());
+  DCHECK(SUCCEEDED(hr));
+
+  ABI::Windows::Foundation::TimeSpan duration =
+      position.duration().ToWinrtTimeSpan();
+
+  hr = timeline_properties->put_EndTime(duration);
+  DCHECK(SUCCEEDED(hr));
+
+  hr = timeline_properties->put_MaxSeekTime(duration);
+  DCHECK(SUCCEEDED(hr));
+
+  hr = system_media_controls_2->UpdateTimelineProperties(
+      timeline_properties.Get());
+  DCHECK(SUCCEEDED(hr));
+
+  hr = system_media_controls_2->put_PlaybackRate(position.playback_rate());
+  DCHECK(SUCCEEDED(hr));
+}
+
 void SystemMediaControlsWin::ClearThumbnail() {
   DCHECK(initialized_);
   DCHECK(display_updater_);
@@ -339,6 +429,11 @@
     obs.OnStop();
 }
 
+void SystemMediaControlsWin::OnSeekTo(const base::TimeDelta& time) {
+  for (SystemMediaControlsObserver& obs : observers_)
+    obs.OnSeekTo(time);
+}
+
 ABI::Windows::Media::MediaPlaybackStatus
 SystemMediaControlsWin::GetSmtcPlaybackStatus(PlaybackStatus status) {
   switch (status) {
@@ -404,6 +499,21 @@
   return S_OK;
 }
 
+// static
+HRESULT SystemMediaControlsWin::PlaybackPositionChangeRequested(
+    ISystemMediaTransportControls* sender,
+    IPlaybackPositionChangeRequestedEventArgs* args) {
+  ABI::Windows::Foundation::TimeSpan position;
+  HRESULT hr = args->get_RequestedPlaybackPosition(&position);
+  if (FAILED(hr))
+    return hr;
+
+  SystemMediaControlsWin* impl = GetInstance();
+  impl->OnSeekTo(base::TimeDelta::FromWinrtTimeSpan(position));
+
+  return S_OK;
+}
+
 }  // namespace internal
 
 }  // namespace system_media_controls
diff --git a/components/system_media_controls/win/system_media_controls_win.h b/components/system_media_controls/win/system_media_controls_win.h
index 1b15118..ed200b2 100644
--- a/components/system_media_controls/win/system_media_controls_win.h
+++ b/components/system_media_controls/win/system_media_controls_win.h
@@ -44,11 +44,13 @@
   void SetIsPreviousEnabled(bool value) override;
   void SetIsPlayPauseEnabled(bool value) override;
   void SetIsStopEnabled(bool value) override;
+  void SetIsSeekToEnabled(bool value) override;
   void SetPlaybackStatus(PlaybackStatus status) override;
   void SetTitle(const std::u16string& title) override;
   void SetArtist(const std::u16string& artist) override;
   void SetAlbum(const std::u16string& album) override {}
   void SetThumbnail(const SkBitmap& bitmap) override;
+  void SetPosition(const media_session::MediaPosition& position) override;
   void ClearThumbnail() override;
   void ClearMetadata() override;
   void UpdateDisplay() override;
@@ -59,6 +61,10 @@
       ABI::Windows::Media::ISystemMediaTransportControlsButtonPressedEventArgs*
           args);
 
+  static HRESULT PlaybackPositionChangeRequested(
+      ABI::Windows::Media::ISystemMediaTransportControls* sender,
+      ABI::Windows::Media::IPlaybackPositionChangeRequestedEventArgs* args);
+
   static SystemMediaControlsWin* instance_;
 
   // Called by ButtonPressed when the particular key is pressed.
@@ -68,6 +74,9 @@
   void OnPrevious();
   void OnStop();
 
+  // Called by PlaybackPositionChangeRequested.
+  void OnSeekTo(const base::TimeDelta& time);
+
   // Converts PlaybackStatus values to SMTC-friendly values.
   ABI::Windows::Media::MediaPlaybackStatus GetSmtcPlaybackStatus(
       PlaybackStatus status);
@@ -88,14 +97,19 @@
       ABI::Windows::Storage::Streams::IRandomAccessStreamReference>
       icon_stream_reference_;
 
-  EventRegistrationToken registration_token_;
+  EventRegistrationToken button_pressed_registration_token_;
+  EventRegistrationToken playback_position_change_requested_registration_token_;
 
   // True if we've already tried to connect to the SystemMediaTransportControls.
   bool attempted_to_initialize_ = false;
 
   // True if we've successfully registered a button handler on the
   // SystemMediaTransportControls.
-  bool has_valid_registration_token_ = false;
+  bool has_valid_button_pressed_registration_token_ = false;
+
+  // True if we've successfully registered a playback position change requested
+  // handler on the SystemMediaTransportControls.
+  bool has_valid_playback_position_change_requested_registration_token_ = false;
 
   // True if we've successfully connected to the SystemMediaTransportControls.
   bool initialized_ = false;
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc
index 652bda5..3da08ab 100644
--- a/components/viz/service/display/dc_layer_overlay.cc
+++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -230,6 +230,7 @@
   dc_layer->color_space = gfx::ColorSpace::CreateSRGB();
 
   // Both color space and protected_video_type are hard-coded for stream video.
+  // TODO(crbug.com/1384544): Consider using quad->protected_video_type.
   if (quad->is_stream_video) {
     dc_layer->color_space = gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT709,
                                             gfx::ColorSpace::TransferID::BT709);
diff --git a/components/webapps/browser/android/add_to_homescreen_coordinator.cc b/components/webapps/browser/android/add_to_homescreen_coordinator.cc
index fdfcd74..b177cf6 100644
--- a/components/webapps/browser/android/add_to_homescreen_coordinator.cc
+++ b/components/webapps/browser/android/add_to_homescreen_coordinator.cc
@@ -24,6 +24,14 @@
     base::RepeatingCallback<void(AddToHomescreenInstaller::Event,
                                  const AddToHomescreenParams&)>
         event_callback) {
+  // Don't start if app info is not available.
+  if ((params->app_type == AddToHomescreenParams::AppType::NATIVE &&
+       params->native_app_data.is_null()) ||
+      (params->app_type == AddToHomescreenParams::AppType::WEBAPK &&
+       !params->shortcut_info)) {
+    return false;
+  }
+
   JNIEnv* env = base::android::AttachCurrentThread();
   AddToHomescreenMediator* mediator = (AddToHomescreenMediator*)
       Java_AddToHomescreenCoordinator_initMvcAndReturnMediator(
diff --git a/components/webapps/browser/android/shortcut_info.cc b/components/webapps/browser/android/shortcut_info.cc
index 8c90c5a..e960a26 100644
--- a/components/webapps/browser/android/shortcut_info.cc
+++ b/components/webapps/browser/android/shortcut_info.cc
@@ -55,14 +55,15 @@
     const GURL& manifest_url,
     const blink::mojom::Manifest& manifest,
     const GURL& primary_icon_url) {
-  auto shortcut_info = std::make_unique<ShortcutInfo>(GURL());
-  if (!blink::IsEmptyManifest(manifest)) {
-    shortcut_info->UpdateFromManifest(manifest);
-    shortcut_info->manifest_url = manifest_url;
-    shortcut_info->best_primary_icon_url = primary_icon_url;
-    shortcut_info->UpdateBestSplashIcon(manifest);
+  if (blink::IsEmptyManifest(manifest)) {
+    return nullptr;
   }
 
+  auto shortcut_info = std::make_unique<ShortcutInfo>(GURL());
+  shortcut_info->UpdateFromManifest(manifest);
+  shortcut_info->manifest_url = manifest_url;
+  shortcut_info->best_primary_icon_url = primary_icon_url;
+  shortcut_info->UpdateBestSplashIcon(manifest);
   return shortcut_info;
 }
 
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 0068f46..730b9dc 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -1071,9 +1071,9 @@
   document_checker.CheckAccessible(GetRendererAccessible());
 
   // Change the children of the document body.
-  AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         ui::kAXModeComplete,
-                                         ax::mojom::Event::kChildrenChanged);
+  AccessibilityNotificationWaiter waiter(
+      shell()->web_contents(), ui::kAXModeComplete,
+      ui::AXEventGenerator::Event::CHILDREN_CHANGED);
   ExecuteScript(u"document.body.innerHTML='<b>new text</b>'");
   ASSERT_TRUE(waiter.WaitForNotification());
 
@@ -1096,9 +1096,9 @@
   document_checker.CheckAccessible(GetRendererAccessible());
 
   // Change the children of the document body.
-  AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         ui::kAXModeComplete,
-                                         ax::mojom::Event::kChildrenChanged);
+  AccessibilityNotificationWaiter waiter(
+      shell()->web_contents(), ui::kAXModeComplete,
+      ui::AXEventGenerator::Event::CHILDREN_CHANGED);
   ExecuteScript(u"document.body.children[0].style.visibility='visible'");
   ASSERT_TRUE(waiter.WaitForNotification());
 
@@ -2093,9 +2093,9 @@
   }
 
   // Delete the character in the input field.
-  AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         ui::kAXModeComplete,
-                                         ax::mojom::Event::kChildrenChanged);
+  AccessibilityNotificationWaiter waiter(
+      shell()->web_contents(), ui::kAXModeComplete,
+      ui::AXEventGenerator::Event::CHILDREN_CHANGED);
   ExecuteScript(u"document.querySelector('[contenteditable]').innerText='';");
   ASSERT_TRUE(waiter.WaitForNotification());
 
@@ -2568,9 +2568,9 @@
 
   base::win::ScopedVariant childid_self(CHILDID_SELF);
   base::win::ScopedBstr new_value(L"New value");
-  AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         ui::kAXModeComplete,
-                                         ax::mojom::Event::kChildrenChanged);
+  AccessibilityNotificationWaiter waiter(
+      shell()->web_contents(), ui::kAXModeComplete,
+      ui::AXEventGenerator::Event::CHILDREN_CHANGED);
   EXPECT_HRESULT_SUCCEEDED(
       paragraph->put_accValue(childid_self, new_value.Get()));
   ASSERT_TRUE(waiter.WaitForNotification());
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
index dff48b3..bb65567 100644
--- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -1085,9 +1085,9 @@
   // Now remove "Node 1" from the DOM and verify the text range created from
   // "Node 1" is still functional.
   {
-    AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                           ui::kAXModeComplete,
-                                           ax::mojom::Event::kChildrenChanged);
+    AccessibilityNotificationWaiter waiter(
+        shell()->web_contents(), ui::kAXModeComplete,
+        ui::AXEventGenerator::Event::CHILDREN_CHANGED);
     EXPECT_TRUE(
         ExecJs(shell()->web_contents(),
                "document.getElementById('wrapper').removeChild(document."
@@ -1104,9 +1104,9 @@
   // Now remove all children from the DOM and verify the text range created from
   // "Node 1" is still valid (it got moved to a non-deleted ancestor node).
   {
-    AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                           ui::kAXModeComplete,
-                                           ax::mojom::Event::kChildrenChanged);
+    AccessibilityNotificationWaiter waiter(
+        shell()->web_contents(), ui::kAXModeComplete,
+        ui::AXEventGenerator::Event::CHILDREN_CHANGED);
     EXPECT_TRUE(ExecJs(shell()->web_contents(),
                        "while(document.body.childElementCount > 0) {"
                        "  document.body.removeChild(document.body.firstChild);"
@@ -3296,7 +3296,7 @@
     EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Before frame");
 
     AccessibilityNotificationWaiter waiter(web_contents, ui::kAXModeComplete,
-                                           ax::mojom::Event::kChildrenChanged);
+                                           ax::mojom::Event::kLayoutComplete);
 
     // Updating the style on that particular node is going to invalidate the
     // leaf text node and will replace it with a new one with the updated style.
@@ -3324,7 +3324,7 @@
         /*expected_count*/ 1);
 
     AccessibilityNotificationWaiter waiter(web_contents, ui::kAXModeComplete,
-                                           ax::mojom::Event::kChildrenChanged);
+                                           ax::mojom::Event::kLayoutComplete);
 
     // Updating the style on that particular node is going to invalidate the
     // leaf text node and will replace it with a new one with the updated style.
@@ -3356,7 +3356,7 @@
         /*expected_count*/ -1);
 
     AccessibilityNotificationWaiter waiter(web_contents, ui::kAXModeComplete,
-                                           ax::mojom::Event::kChildrenChanged);
+                                           ax::mojom::Event::kEndOfTest);
 
     // Updating the style on that particular node is going to invalidate the
     // leaf text node and will replace it with a new one with the updated style.
@@ -3365,6 +3365,7 @@
         web_contents,
         "document.getElementById('s2').style.outline = '1px solid black';"));
 
+    GetManager()->SignalEndOfTest();
     ASSERT_TRUE(waiter.WaitForNotification());
     EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"iframe\nAfter frame");
   }
@@ -3394,8 +3395,9 @@
     // Reloading changes the tree id, triggering an AXTreeManager replacement.
     shell()->Reload();
 
-    AccessibilityNotificationWaiter waiter(web_contents, ui::kAXModeComplete,
-                                           ax::mojom::Event::kChildrenChanged);
+    AccessibilityNotificationWaiter waiter(
+        web_contents, ui::kAXModeComplete,
+        ui::AXEventGenerator::Event::FOCUS_CHANGED);
 
     // We do a style change here only to trigger an AXTree update - apparently,
     // a shell reload doesn't update the tree by itself.
@@ -3433,13 +3435,14 @@
         /*expected_count*/ 1);
 
     AccessibilityNotificationWaiter waiter(web_contents, ui::kAXModeComplete,
-                                           ax::mojom::Event::kChildrenChanged);
+                                           ax::mojom::Event::kEndOfTest);
 
     // We do a style change here only to trigger an AXTree update.
     EXPECT_TRUE(ExecJs(
         web_contents,
         "document.getElementById('s2').style.outline = '1px solid black';"));
 
+    GetManager()->SignalEndOfTest();
     ASSERT_TRUE(waiter.WaitForNotification());
 
     // If the previous observer was not removed correctly, this will cause a
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index 07af6bd..98cca66 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -776,13 +776,16 @@
     // If there is a popup, expand it and wait for it to appear.
     // If it's a list, it will simply click on the list.
     {
-      AccessibilityNotificationWaiter waiter(
-          shell()->web_contents(), ui::kAXModeComplete,
-          ax::mojom::Event::kChildrenChanged);
+      // Note: the kEndOfTextSignal actually represents the next step in the
+      // test, when a response is received from the SignalEndOfTest() call.
+      AccessibilityNotificationWaiter waiter(shell()->web_contents(),
+                                             ui::kAXModeComplete,
+                                             ax::mojom::Event::kEndOfTest);
 
       ui::AXActionData action_data;
       action_data.action = ax::mojom::Action::kDoDefault;
       select->AccessibilityPerformAction(action_data);
+      GetManager()->SignalEndOfTest();
       ASSERT_TRUE(waiter.WaitForNotification());
     }
 
@@ -859,10 +862,10 @@
   }
 
   // Open popup.
-  AccessibilityNotificationWaiter waiter(shell()->web_contents(),
-                                         ui::kAXModeComplete,
-                                         ax::mojom::Event::kChildrenChanged);
   {
+    AccessibilityNotificationWaiter waiter(
+        shell()->web_contents(), ui::kAXModeComplete,
+        ui::AXEventGenerator::Event::EXPANDED);
     ui::AXActionData action_data;
     action_data.action = ax::mojom::Action::kDoDefault;
     select->AccessibilityPerformAction(action_data);
@@ -901,6 +904,9 @@
 
   // Close the popup.
   {
+    AccessibilityNotificationWaiter waiter(
+        shell()->web_contents(), ui::kAXModeComplete,
+        ui::AXEventGenerator::Event::COLLAPSED);
     ui::AXActionData action_data;
     action_data.action = ax::mojom::Action::kDoDefault;
     select->AccessibilityPerformAction(action_data);
diff --git a/content/browser/attribution_reporting/attribution_debug_report.cc b/content/browser/attribution_reporting/attribution_debug_report.cc
index fb1e2d5..6361ec4 100644
--- a/content/browser/attribution_reporting/attribution_debug_report.cc
+++ b/content/browser/attribution_reporting/attribution_debug_report.cc
@@ -167,7 +167,7 @@
     case DebugDataType::kTriggerEventNoise:
       return "trigger-event-noise";
     case DebugDataType::kTriggerEventLowPriority:
-      return "trigger-event-low-prioirty";
+      return "trigger-event-low-priority";
     case DebugDataType::kTriggerEventExcessiveReports:
       return "trigger-event-excessive-reports";
     case DebugDataType::kTriggerEventStorageLimit:
diff --git a/content/browser/attribution_reporting/attribution_debug_report_unittest.cc b/content/browser/attribution_reporting/attribution_debug_report_unittest.cc
index 91622045..3ebb965 100644
--- a/content/browser/attribution_reporting/attribution_debug_report_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_debug_report_unittest.cc
@@ -442,7 +442,7 @@
            "source_type": "navigation",
            "trigger_data": "0"
          },
-         "type": "trigger-event-low-prioirty"
+         "type": "trigger-event-low-priority"
        }])json"},
       {EventLevelResult::kDroppedForNoise,
        /*replaced_event_level_report=*/absl::nullopt,
diff --git a/content/browser/attribution_reporting/attribution_internals.mojom b/content/browser/attribution_reporting/attribution_internals.mojom
index 583e3df..be26521f 100644
--- a/content/browser/attribution_reporting/attribution_internals.mojom
+++ b/content/browser/attribution_reporting/attribution_internals.mojom
@@ -99,6 +99,7 @@
   map<string, string> aggregation_keys;
   uint64 aggregatable_budget_consumed;
   array<uint64> aggregatable_dedup_keys;
+  bool debug_reporting_enabled;
 
   // Union of `StorableSource::Result` and `StoredSource::AttributionLogic`.
   enum Attributability {
@@ -146,6 +147,7 @@
   array<WebUIAggregatableTriggerData> aggregatable_triggers;
   map<string, uint32> aggregatable_values;
   DedupKey? aggregatable_dedup_key;
+  bool debug_reporting_enabled;
 
   enum Status {
     // Shared statuses:
diff --git a/content/browser/attribution_reporting/attribution_internals_browsertest.cc b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
index 902a62d..8ad00fb 100644
--- a/content/browser/attribution_reporting/attribution_internals_browsertest.cc
+++ b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
@@ -305,7 +305,7 @@
       StorableSource::Result::kInsufficientUniqueDestinationCapacity);
 
   manager()->NotifySourceHandled(
-      SourceBuilder(now + base::Hours(7)).Build(),
+      SourceBuilder(now + base::Hours(7)).SetDebugReporting(true).Build(),
       StorableSource::Result::kExcessiveReportingOrigins);
 
   static constexpr char wait_script[] = R"(
@@ -336,7 +336,9 @@
           table.children[3].children[1].innerText === "Rejected: internal error" &&
           table.children[4].children[1].innerText === "Rejected: insufficient source capacity" &&
           table.children[5].children[1].innerText === "Rejected: insufficient unique destination capacity" &&
-          table.children[6].children[1].innerText === "Rejected: excessive reporting origins") {
+          table.children[6].children[1].innerText === "Rejected: excessive reporting origins" &&
+          table.children[5].children[15].innerText === "disabled" &&
+          table.children[6].children[15].innerText === "enabled") {
         obs.disconnect();
         document.title = $3;
       }
@@ -1085,7 +1087,8 @@
             table.children[0].children[8].innerText === $2 &&
             table.children[0].children[9].innerText === $3 &&
             table.children[0].children[10].innerText === '{ "a": 123, "b": 456}' &&
-            table.children[0].children[11].innerText === "18") {
+            table.children[0].children[11].innerText === "18" &&
+            table.children[0].children[12].innerText === "disabled") {
           obs.disconnect();
           document.title = $1;
         }
diff --git a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
index 6387667..8f2df9a2 100644
--- a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
+++ b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
@@ -71,7 +71,8 @@
     Attributability attributability,
     const std::vector<uint64_t>& dedup_keys,
     int64_t aggregatable_budget_consumed,
-    const std::vector<uint64_t>& aggregatable_dedup_keys) {
+    const std::vector<uint64_t>& aggregatable_dedup_keys,
+    bool debug_reporting_enabled) {
   DCHECK_GE(aggregatable_budget_consumed, 0);
   return attribution_internals::mojom::WebUISource::New(
       source.source_event_id(), source.source_origin(),
@@ -86,7 +87,8 @@
             return std::make_pair(key.first,
                                   HexEncodeAggregationKey(key.second));
           }),
-      aggregatable_budget_consumed, aggregatable_dedup_keys, attributability);
+      aggregatable_budget_consumed, aggregatable_dedup_keys,
+      debug_reporting_enabled, attributability);
 }
 
 void ForwardSourcesToWebUI(
@@ -114,10 +116,13 @@
       }
     }
 
-    web_ui_sources.push_back(WebUISource(source.common_info(), attributability,
-                                         source.dedup_keys(),
-                                         source.aggregatable_budget_consumed(),
-                                         source.aggregatable_dedup_keys()));
+    // Note that debug reporting may be enabled when the source was registered
+    // but the value was not persisted in memory. Showing "disabled" in
+    // internals UI as the value is not relevant at this point.
+    web_ui_sources.push_back(WebUISource(
+        source.common_info(), attributability, source.dedup_keys(),
+        source.aggregatable_budget_consumed(), source.aggregatable_dedup_keys(),
+        /*debug_reporting_enabled=*/false));
   }
 
   std::move(web_ui_callback).Run(std::move(web_ui_sources));
@@ -332,7 +337,7 @@
   auto web_ui_source =
       WebUISource(source.common_info(), attributability, /*dedup_keys=*/{},
                   /*aggregatable_budget_consumed=*/0,
-                  /*aggregatable_dedup_keys=*/{});
+                  /*aggregatable_dedup_keys=*/{}, source.debug_reporting());
 
   for (auto& observer : observers_) {
     observer->OnSourceRejected(web_ui_source.Clone());
@@ -518,6 +523,7 @@
       registration.aggregatable_values.values();
   web_ui_trigger->aggregatable_dedup_key =
       CreateWebUIDedupKey(registration.aggregatable_dedup_key);
+  web_ui_trigger->debug_reporting_enabled = registration.debug_reporting;
 
   for (auto& observer : observers_) {
     observer->OnTriggerHandled(web_ui_trigger.Clone());
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.cc b/content/browser/attribution_reporting/attribution_manager_impl.cc
index 7fe0d561..95fedf2 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl.cc
@@ -1031,6 +1031,15 @@
   if (!base::FeatureList::IsEnabled(kAttributionVerboseDebugReporting))
     return;
 
+  if (!IsOperationAllowed(storage_partition_.get(),
+                          ContentBrowserClient::AttributionReportingOperation::
+                              kSourceVerboseDebugReport,
+                          &*source.common_info().source_origin(),
+                          /*destination_origin=*/nullptr,
+                          &*source.common_info().reporting_origin())) {
+    return;
+  }
+
   if (absl::optional<AttributionDebugReport> debug_report =
           AttributionDebugReport::Create(source, is_debug_cookie_set, result)) {
     report_sender_->SendReport(std::move(*debug_report));
@@ -1044,6 +1053,15 @@
   if (!base::FeatureList::IsEnabled(kAttributionVerboseDebugReporting))
     return;
 
+  if (!IsOperationAllowed(storage_partition_.get(),
+                          ContentBrowserClient::AttributionReportingOperation::
+                              kTriggerVerboseDebugReport,
+                          /*source_origin=*/nullptr,
+                          &*trigger.destination_origin(),
+                          &*trigger.registration().reporting_origin)) {
+    return;
+  }
+
   if (absl::optional<AttributionDebugReport> debug_report =
           AttributionDebugReport::Create(trigger, is_debug_cookie_set,
                                          result)) {
diff --git a/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc b/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
index 0f60075..12abc7c 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
@@ -1255,6 +1255,13 @@
           Pointee(url::Origin::Create(GURL("https://impression.test/"))),
           IsNull(), Pointee(url::Origin::Create(GURL("https://report.test/")))))
       .WillOnce(Return(false));
+  EXPECT_CALL(browser_client,
+              IsAttributionReportingOperationAllowed(
+                  _,
+                  ContentBrowserClient::AttributionReportingOperation::
+                      kSourceVerboseDebugReport,
+                  _, _, _))
+      .WillOnce(Return(true));
   ScopedContentBrowserClientSetting setting(&browser_client);
 
   attribution_manager_->HandleSource(source);
@@ -1289,8 +1296,13 @@
   EXPECT_CALL(
       browser_client,
       IsAttributionReportingOperationAllowed(
-          _, ContentBrowserClient::AttributionReportingOperation::kSource, _, _,
-          _))
+          _,
+          AnyOf(ContentBrowserClient::AttributionReportingOperation::kSource,
+                ContentBrowserClient::AttributionReportingOperation::
+                    kSourceVerboseDebugReport,
+                ContentBrowserClient::AttributionReportingOperation::
+                    kTriggerVerboseDebugReport),
+          _, _, _))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(
       browser_client,
@@ -1320,7 +1332,11 @@
       IsAttributionReportingOperationAllowed(
           _,
           AnyOf(ContentBrowserClient::AttributionReportingOperation::kSource,
-                ContentBrowserClient::AttributionReportingOperation::kTrigger),
+                ContentBrowserClient::AttributionReportingOperation::kTrigger,
+                ContentBrowserClient::AttributionReportingOperation::
+                    kSourceVerboseDebugReport,
+                ContentBrowserClient::AttributionReportingOperation::
+                    kTriggerVerboseDebugReport),
           _, _, _))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(
@@ -1372,7 +1388,11 @@
       IsAttributionReportingOperationAllowed(
           _,
           AnyOf(ContentBrowserClient::AttributionReportingOperation::kSource,
-                ContentBrowserClient::AttributionReportingOperation::kTrigger),
+                ContentBrowserClient::AttributionReportingOperation::kTrigger,
+                ContentBrowserClient::AttributionReportingOperation::
+                    kSourceVerboseDebugReport,
+                ContentBrowserClient::AttributionReportingOperation::
+                    kTriggerVerboseDebugReport),
           _, _, _))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(
@@ -1652,7 +1672,7 @@
         123,
         "https://r2.test",
         absl::nullopt,
-        123
+        123,
     },
     {
         "no debug key, has cookie",
@@ -2110,6 +2130,38 @@
   }
 }
 
+TEST_F(AttributionManagerImplTest,
+       EmbedderDisallowsTriggerVerboseDebugReport_NoReportSent) {
+  url::Origin reporting_origin = url::Origin::Create(GURL("https://r1.test"));
+  cookie_checker_->AddOriginWithDebugCookieSet(reporting_origin);
+
+  MockAttributionReportingContentBrowserClient browser_client;
+  EXPECT_CALL(
+      browser_client,
+      IsAttributionReportingOperationAllowed(
+          _, ContentBrowserClient::AttributionReportingOperation::kTrigger, _,
+          _, _))
+      .WillOnce(Return(true));
+  EXPECT_CALL(
+      browser_client,
+      IsAttributionReportingOperationAllowed(
+          _,
+          ContentBrowserClient::AttributionReportingOperation::
+              kTriggerVerboseDebugReport,
+          IsNull(),
+          Pointee(url::Origin::Create(GURL("https://sub.conversion.test/"))),
+          Pointee(reporting_origin)))
+      .WillOnce(Return(false));
+  ScopedContentBrowserClientSetting setting(&browser_client);
+
+  attribution_manager_->HandleTrigger(TriggerBuilder()
+                                          .SetReportingOrigin(reporting_origin)
+                                          .SetDebugReporting(true)
+                                          .Build());
+  task_environment_.RunUntilIdle();
+  EXPECT_THAT(report_sender_->verbose_debug_calls(), IsEmpty());
+}
+
 class AttributionManagerImplDebugReportTest
     : public AttributionManagerImplTest {
  protected:
@@ -2194,6 +2246,40 @@
   }
 }
 
+TEST_F(AttributionManagerImplDebugReportTest,
+       EmbedderDisallowsSourceVerboseDebugReport_NoReportSent) {
+  MockAttributionReportingContentBrowserClient browser_client;
+  EXPECT_CALL(
+      browser_client,
+      IsAttributionReportingOperationAllowed(
+          _, ContentBrowserClient::AttributionReportingOperation::kSource, _, _,
+          _))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(
+      browser_client,
+      IsAttributionReportingOperationAllowed(
+          _,
+          ContentBrowserClient::AttributionReportingOperation::
+              kSourceVerboseDebugReport,
+          Pointee(url::Origin::Create(GURL("https://impression.test/"))),
+          IsNull(), Pointee(url::Origin::Create(GURL("https://report.test/")))))
+      .WillRepeatedly(Return(false));
+  ScopedContentBrowserClientSetting setting(&browser_client);
+
+  attribution_manager_->HandleSource(SourceBuilder().Build());
+
+  attribution_manager_->HandleSource(
+      SourceBuilder()
+          .SetDestinationOrigin(url::Origin::Create(GURL("https://d.test")))
+          .SetDebugReporting(true)
+          .Build());
+
+  task_environment_.RunUntilIdle();
+
+  EXPECT_THAT(StoredSources(), SizeIs(1));
+  EXPECT_THAT(report_sender_->verbose_debug_calls(), IsEmpty());
+}
+
 class AttributionManagerImplCookieBasedDebugReportTest
     : public AttributionManagerImplTest {
  protected:
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 1e3da760..5c94a1d2 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -196,7 +196,8 @@
       receiver_.BindNewEndpointAndPassRemote(),
       session_.BindNewEndpointAndPassReceiver(),
       io_session_.BindNewPipeAndPassReceiver(), session_state_cookie_.Clone(),
-      client_->UsesBinaryProtocol(), client_->IsTrusted(), session_id_);
+      client_->UsesBinaryProtocol(), client_->IsTrusted(), session_id_,
+      IsWaitingForDebuggerOnStart());
   session_.set_disconnect_handler(base::BindOnce(
       &DevToolsSession::MojoConnectionDestroyed, base::Unretained(this)));
 
@@ -593,11 +594,13 @@
     const std::string& session_id,
     DevToolsAgentHostImpl* agent_host,
     DevToolsAgentHostClient* client,
-    Mode mode) {
+    Mode mode,
+    base::OnceClosure resume_callback) {
   DCHECK(!agent_host->SessionByClient(client));
   DCHECK(!root_session_);
   std::unique_ptr<DevToolsSession> session(
       new DevToolsSession(client, session_id, this, mode));
+  session->SetRuntimeResumeCallback(std::move(resume_callback));
   DevToolsSession* session_ptr = session.get();
   // If attach did not succeed, |session| is already destroyed.
   if (!agent_host->AttachInternal(std::move(session)))
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index df71e01..ad9c3e5c 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -111,7 +111,8 @@
   DevToolsSession* AttachChildSession(const std::string& session_id,
                                       DevToolsAgentHostImpl* agent_host,
                                       DevToolsAgentHostClient* client,
-                                      Mode mode);
+                                      Mode mode,
+                                      base::OnceClosure resume_callback);
   void DetachChildSession(const std::string& session_id);
   bool HasChildSession(const std::string& session_id);
   Mode session_mode() const { return mode_; }
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index b1421f9..f1ad055 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -413,14 +413,15 @@
               ? Mode::kSupportsTabTarget
               : handler->session_mode_;
 
-      DevToolsSession* devtools_session =
-          handler->root_session_->AttachChildSession(id, agent_host_impl,
-                                                     session, mode);
-      if (waiting_for_debugger && devtools_session) {
-        devtools_session->SetRuntimeResumeCallback(base::BindOnce(
-            &Session::ResumeIfThrottled, base::Unretained(session)));
-        session->devtools_session_ = devtools_session;
+      base::OnceClosure resume_callback;
+      if (waiting_for_debugger) {
+        resume_callback = base::BindOnce(&Session::ResumeIfThrottled,
+                                         base::Unretained(session));
       }
+      DevToolsSession* devtools_session =
+          handler->root_session_->AttachChildSession(
+              id, agent_host_impl, session, mode, std::move(resume_callback));
+      session->devtools_session_ = devtools_session;
     } else {
       agent_host_impl->AttachClient(session);
     }
diff --git a/content/browser/display_cutout/OWNERS b/content/browser/display_cutout/OWNERS
deleted file mode 100644
index 9e31bde3..0000000
--- a/content/browser/display_cutout/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://chrome/android/java/src/org/chromium/chrome/browser/display_cutout/OWNERS
diff --git a/content/browser/fenced_frame/fenced_frame_browsertest.cc b/content/browser/fenced_frame/fenced_frame_browsertest.cc
index f15a947..ba69ce62 100644
--- a/content/browser/fenced_frame/fenced_frame_browsertest.cc
+++ b/content/browser/fenced_frame/fenced_frame_browsertest.cc
@@ -4499,10 +4499,43 @@
     // destination will be the ultimate destination of the navigation.
     std::vector<Destination> redirects;
 
-    // Whether the reportEvent should succeed.
-    bool should_have_metadata = false;
+    // Specify the outcome of reportEvent.
+    enum class Result {
+      kSuccess,
+      kModeNotOpaque,
+      kCrossOrigin,
+      kNoMeta,
+      kNoDestination,
+      kNoReportingURL,
+      kInvalidReportingURL
+    };
+
+    // Outcome of reportEvent.
+    Result report_event_result = Result::kSuccess;
   };
 
+  std::string GetConsoleWarningPattern(Step::Result result) {
+    switch (result) {
+      case Step::Result::kModeNotOpaque:
+        return "fence.reportEvent is only available in the 'opaque-ads' mode.";
+      case Step::Result::kCrossOrigin:
+        return "fence.reportEvent is only available in same-origin subframes.";
+      case Step::Result::kNoMeta:
+        return "This frame did not register reporting metadata.";
+      case Step::Result::kNoDestination:
+        return "This frame did not register reporting metadata for "
+               "destination*";
+      case Step::Result::kNoReportingURL:
+        return "This frame did not register reporting url for destination (.*) "
+               "and event_type (.*)";
+      case Step::Result::kInvalidReportingURL:
+        return "This frame registered invalid reporting url for destination "
+               "(.*) and event_type (.*)";
+      default:
+        return "";
+    }
+  }
+
   // A helper function for specifying reportEvent tests. Each step consists of a
   // series of `Step`s specified above.
   void RunTest(std::vector<Step>& steps) {
@@ -4651,6 +4684,19 @@
                     ->GetLastCommittedOrigin());
       navigation_index++;
 
+      // Monitor the console warnings.
+      WebContentsConsoleObserver console_observer(web_contents());
+      auto filter =
+          [](const content::WebContentsConsoleObserver::Message& message) {
+            return message.log_level ==
+                   blink::mojom::ConsoleMessageLevel::kWarning;
+          };
+      console_observer.SetFilter(base::BindRepeating(filter));
+      if (step.report_event_result != Step::Result::kSuccess) {
+        console_observer.SetPattern(
+            GetConsoleWarningPattern(step.report_event_result));
+      }
+
       // Perform the reportEvent call, with a unique body.
       const char report_event_script[] = R"(
         window.fence.reportEvent({
@@ -4663,13 +4709,16 @@
                          JsReplace(report_event_script, navigation_index)));
 
       // If relevant, check that the event report succeeded.
-      if (step.should_have_metadata) {
+      if (step.report_event_result == Step::Result::kSuccess) {
         auto& response = *responses[response_index];
         response.WaitForRequest();
         EXPECT_EQ(response.http_request()->content,
                   JsReplace("click $1", navigation_index));
         response.Done();
         response_index++;
+      } else {
+        EXPECT_FALSE(console_observer.messages().empty());
+        EXPECT_EQ(console_observer.messages().size(), 1u);
       }
     }
 
@@ -4696,7 +4745,7 @@
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
   };
   RunTest(config);
@@ -4710,12 +4759,12 @@
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
       {
           .is_target_nested_iframe = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
   };
   RunTest(config);
@@ -4730,12 +4779,12 @@
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
       {
           .is_target_nested_iframe = true,
           .destination = {"b.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = false,
+          .report_event_result = Step::Result::kCrossOrigin,
       },
   };
   RunTest(config);
@@ -4750,11 +4799,11 @@
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
       {
           .destination = {"a.test", "/fenced_frames/title1.html?foo"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
   };
   RunTest(config);
@@ -4769,17 +4818,17 @@
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
       {
           .destination = {"b.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = false,
+          .report_event_result = Step::Result::kNoMeta,
       },
       {
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
   };
   RunTest(config);
@@ -4793,13 +4842,13 @@
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
       {
           .is_embedder_initiated = true,
           .is_opaque = false,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = false,
+          .report_event_result = Step::Result::kNoMeta,
       },
   };
   RunTest(config);
@@ -4819,7 +4868,7 @@
                   {"a.test", "/fenced_frames/redirect2.html"},
                   {"a.test", "/fenced_frames/title1.html"},
               },
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
   };
   RunTest(config);
@@ -4839,7 +4888,7 @@
                   {"b.test", "/fenced_frames/redirect2.html"},
                   {"c.test", "/fenced_frames/title1.html"},
               },
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
   };
   RunTest(config);
@@ -4854,7 +4903,7 @@
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
       {
           .destination = {"a.test", "/fenced_frames/redirect1.html"},
@@ -4863,7 +4912,7 @@
                   {"a.test", "/fenced_frames/redirect2.html"},
                   {"a.test", "/fenced_frames/title1.html?foo"},
               },
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
   };
   RunTest(config);
@@ -4878,7 +4927,7 @@
           .is_embedder_initiated = true,
           .is_opaque = true,
           .destination = {"a.test", "/fenced_frames/title1.html"},
-          .should_have_metadata = true,
+          .report_event_result = Step::Result::kSuccess,
       },
       {
           .destination = {"a.test", "/fenced_frames/redirect1.html"},
@@ -4887,7 +4936,7 @@
                   {"b.test", "/fenced_frames/redirect2.html"},
                   {"a.test", "/fenced_frames/title1.html"},
               },
-          .should_have_metadata = false,
+          .report_event_result = Step::Result::kNoMeta,
       },
   };
   RunTest(config);
diff --git a/content/browser/first_party_sets/database/first_party_sets_database.cc b/content/browser/first_party_sets/database/first_party_sets_database.cc
index 336781e..77ea4b71 100644
--- a/content/browser/first_party_sets/database/first_party_sets_database.cc
+++ b/content/browser/first_party_sets/database/first_party_sets_database.cc
@@ -37,7 +37,7 @@
 namespace {
 
 // Version number of the database.
-const int kCurrentVersionNumber = 3;
+const int kCurrentVersionNumber = 4;
 
 // Earliest version which can use a |kCurrentVersionNumber| database
 // without failing.
@@ -115,15 +115,15 @@
   if (!db.Execute(kPolicyConfigurationsSql))
     return false;
 
-  static constexpr char kManualSetsSql[] =
-      "CREATE TABLE IF NOT EXISTS manual_sets("
+  static constexpr char kManualConfigurationsSql[] =
+      "CREATE TABLE IF NOT EXISTS manual_configurations("
       "browser_context_id TEXT NOT NULL,"
       "site TEXT NOT NULL,"
-      "primary_site TEXT NOT NULL,"
-      "site_type INTEGER NOT NULL,"
+      "primary_site TEXT,"  // May be NULL if this row represents a deletion.
+      "site_type INTEGER,"  // May be NULL if this row represents a deletion.
       "PRIMARY KEY(browser_context_id,site)"
       ")WITHOUT ROWID";
-  if (!db.Execute(kManualSetsSql))
+  if (!db.Execute(kManualConfigurationsSql))
     return false;
 
   return true;
@@ -162,7 +162,7 @@
     return false;
   }
 
-  if (!InsertManualSets(browser_context_id, sets.manual_sets()))
+  if (!InsertManualConfiguration(browser_context_id, sets))
     return false;
 
   if (!InsertPolicyConfigurations(browser_context_id, config))
@@ -326,38 +326,43 @@
       });
 }
 
-bool FirstPartySetsDatabase::InsertManualSets(
+bool FirstPartySetsDatabase::InsertManualConfiguration(
     const std::string& browser_context_id,
-    const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>&
-        manual_sets) {
+    const net::GlobalFirstPartySets& global_first_party_sets) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(db_status_, InitStatus::kSuccess);
   DCHECK(db_->HasActiveTransactions());
 
   static constexpr char kDeleteSql[] =
-      "DELETE FROM manual_sets WHERE browser_context_id=?";
+      "DELETE FROM manual_configurations WHERE browser_context_id=?";
   sql::Statement delete_statement(
       db_->GetCachedStatement(SQL_FROM_HERE, kDeleteSql));
   delete_statement.BindString(0, browser_context_id);
   if (!delete_statement.Run())
     return false;
 
-  for (const auto& [site, entry] : manual_sets) {
-    DCHECK(!site.opaque());
-    static constexpr char kInsertSql[] =
-        "INSERT INTO "
-        "manual_sets(browser_context_id,site,primary_site,site_type)"
-        "VALUES(?,?,?,?)";
-    sql::Statement insert_statement(
-        db_->GetCachedStatement(SQL_FROM_HERE, kInsertSql));
-    insert_statement.BindString(0, browser_context_id);
-    insert_statement.BindString(1, site.Serialize());
-    insert_statement.BindString(2, entry.primary().Serialize());
-    insert_statement.BindInt(3, static_cast<int>(entry.site_type()));
-
-    if (!insert_statement.Run())
-      return false;
-  }
+  global_first_party_sets.ForEachManualConfigEntry(
+      [&](const net::SchemefulSite& site,
+          const absl::optional<net::FirstPartySetEntry>& entry) -> bool {
+        DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+        DCHECK(!site.opaque());
+        static constexpr char kInsertSql[] =
+            "INSERT INTO manual_configurations"
+            "(browser_context_id,site,primary_site,site_type)"
+            "VALUES(?,?,?,?)";
+        sql::Statement insert_statement(
+            db_->GetCachedStatement(SQL_FROM_HERE, kInsertSql));
+        insert_statement.BindString(0, browser_context_id);
+        insert_statement.BindString(1, site.Serialize());
+        if (entry.has_value()) {
+          insert_statement.BindString(2, entry->primary().Serialize());
+          insert_statement.BindInt(3, static_cast<int>(entry->site_type()));
+        } else {
+          insert_statement.BindNull(2);
+          insert_statement.BindNull(3);
+        }
+        return insert_statement.Run();
+      });
   return true;
 }
 
@@ -419,8 +424,11 @@
   net::GlobalFirstPartySets global_sets(base::Version(version), entries,
                                         /*aliases=*/{});
 
-  // Query & apply manual set.
-  global_sets.ApplyManuallySpecifiedSet(FetchManualSets(browser_context_id));
+  // Query & apply manual configuration. Safe because this config and this
+  // public sets data were written during the same run of Chrome, and the config
+  // was computed from that data.
+  global_sets.UnsafeSetManualConfig(
+      FetchManualConfiguration(browser_context_id));
 
   return global_sets;
 }
@@ -604,17 +612,20 @@
   return statement.Step() && statement.Succeeded();
 }
 
-base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>
-FirstPartySetsDatabase::FetchManualSets(const std::string& browser_context_id) {
+net::FirstPartySetsContextConfig
+FirstPartySetsDatabase::FetchManualConfiguration(
+    const std::string& browser_context_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!LazyInit())
     return {};
 
-  std::vector<std::pair<net::SchemefulSite, net::FirstPartySetEntry>> results;
+  std::vector<
+      std::pair<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>>>
+      results;
   static constexpr char kSelectSql[] =
       // clang-format off
-      "SELECT site,primary_site,site_type FROM manual_sets "
+      "SELECT site,primary_site,site_type FROM manual_configurations "
       "WHERE browser_context_id=?";
   // clang-format on
   sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSelectSql));
@@ -625,27 +636,39 @@
         FirstPartySetParser::CanonicalizeRegisteredDomain(
             statement.ColumnString(0), /*emit_errors=*/false);
 
-    absl::optional<net::SchemefulSite> primary =
-        FirstPartySetParser::CanonicalizeRegisteredDomain(
-            statement.ColumnString(1), /*emit_errors=*/false);
+    absl::optional<net::SchemefulSite> maybe_primary_site;
+    absl::optional<net::SiteType> maybe_site_type;
+    // DB entry for "deleted"  site will have null `primary_site` and
+    // `site_type`.
+    if (std::string primary_site = statement.ColumnString(1);
+        !primary_site.empty()) {
+      maybe_primary_site = FirstPartySetParser::CanonicalizeRegisteredDomain(
+          primary_site, /*emit_errors=*/false);
 
-    absl::optional<net::SiteType> site_type =
-        net::FirstPartySetEntry::DeserializeSiteType(statement.ColumnInt(2));
+      maybe_site_type =
+          net::FirstPartySetEntry::DeserializeSiteType(statement.ColumnInt(2));
+    }
 
     // TODO(crbug.com/1314039): Invalid entries should be rare case but
     // possible. Consider deleting them from DB.
-    if (site.has_value() && primary.has_value() && site_type.has_value()) {
+    if (site.has_value()) {
       results.emplace_back(
           std::move(site.value()),
-          net::FirstPartySetEntry(primary.value(), site_type.value(),
-                                  /*site_index=*/absl::nullopt));
+          maybe_primary_site.has_value() && maybe_site_type.has_value()
+              ? absl::make_optional(net::FirstPartySetEntry(
+                    maybe_primary_site.value(),
+                    // TODO(https://crbug.com/1219656): May change to use the
+                    // real site_index in the future, depending on the design
+                    // details. Use null site index for now.
+                    maybe_site_type.value(), absl::nullopt))
+              : absl::nullopt);
     }
   }
 
   if (!statement.Succeeded())
     return {};
 
-  return results;
+  return net::FirstPartySetsContextConfig(std::move(results));
 }
 
 bool FirstPartySetsDatabase::LazyInit() {
@@ -766,10 +789,12 @@
 }
 
 bool FirstPartySetsDatabase::UpgradeSchema() {
-  if (meta_table_.GetVersionNumber() == 2) {
-    if (!MigrateToVersion3())
-      return false;
-  }
+  if (meta_table_.GetVersionNumber() == 2 && !MigrateToVersion3())
+    return false;
+
+  if (meta_table_.GetVersionNumber() == 3 && !MigrateToVersion4())
+    return false;
+
   // Add similar if () blocks for new versions here.
 
   return true;
@@ -787,6 +812,34 @@
   return true;
 }
 
+bool FirstPartySetsDatabase::MigrateToVersion4() {
+  DCHECK(db_->HasActiveTransactions());
+  // Create manual_configurations table; transfer data from manual_sets table to
+  // manual_configurations table; drop manual_sets table.
+  bool success = db_->Execute(
+                     "CREATE TABLE manual_configurations("
+                     "browser_context_id TEXT NOT NULL,"
+                     "site TEXT NOT NULL,"
+                     "primary_site TEXT,"  // May be NULL if this row represents
+                                           // a deletion.
+                     "site_type INTEGER,"  // May be NULL if this row represents
+                                           // a deletion.
+                     "PRIMARY KEY(browser_context_id,site)"
+                     ")WITHOUT ROWID") &&
+                 db_->Execute(
+                     "INSERT INTO manual_configurations"
+                     "(browser_context_id,site,primary_site,site_type) "
+                     "SELECT browser_context_id,site,primary_site,site_type "
+                     "FROM manual_sets") &&
+                 db_->Execute("DROP TABLE manual_sets");
+
+  if (!success)
+    return false;
+
+  meta_table_.SetVersionNumber(4);
+  return true;
+}
+
 void FirstPartySetsDatabase::IncreaseRunCount() {
   DCHECK_EQ(db_status_, InitStatus::kSuccess);
   // 0 is the default value, `run_count_` should only be set once.
diff --git a/content/browser/first_party_sets/database/first_party_sets_database.h b/content/browser/first_party_sets/database/first_party_sets_database.h
index b520e8a8..3d4fc35 100644
--- a/content/browser/first_party_sets/database/first_party_sets_database.h
+++ b/content/browser/first_party_sets/database/first_party_sets_database.h
@@ -21,7 +21,6 @@
 #include "sql/meta_table.h"
 
 namespace net {
-class FirstPartySetEntry;
 class FirstPartySetsCacheFilter;
 class FirstPartySetsContextConfig;
 class GlobalFirstPartySets;
@@ -120,24 +119,24 @@
   [[nodiscard]] bool SetPublicSets(const std::string& browser_context_id,
                                    const net::GlobalFirstPartySets& sets);
 
-  // Stores the Manual Sets into manual_sets table, and returns true on success.
-  // Inserting new manual sets will wipe out pre-existing manual sets for the
-  // given 'browser_context_id'
-  [[nodiscard]] bool InsertManualSets(
+  // Stores the manual configuration into manual_configurations table, and
+  // returns true on success. Inserting new manual configuration will wipe out
+  // pre-existing entries for the given 'browser_context_id'
+  [[nodiscard]] bool InsertManualConfiguration(
       const std::string& browser_context_id,
-      const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>&
-          manual_sets);
+      const net::GlobalFirstPartySets& global_first_party_sets);
 
   // Stores the policy configurations into policy_configurations table, and
   // returns true on success. Note that inserting new configurations will
   // wipe out the pre-existing ones for the given `browser_context_id`.
   [[nodiscard]] bool InsertPolicyConfigurations(
       const std::string& browser_context_id,
-      const net::FirstPartySetsContextConfig& config);
+      const net::FirstPartySetsContextConfig& policy_config);
 
-  // Gets the previously-stored manual_sets for the `browser_context_id`.
-  [[nodiscard]] base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>
-  FetchManualSets(const std::string& browser_context_id);
+  // Gets the previously-stored manual configuration for the
+  // `browser_context_id`.
+  [[nodiscard]] net::FirstPartySetsContextConfig FetchManualConfiguration(
+      const std::string& browser_context_id);
 
   // Gets the list of sites to clear for the `browser_context_id`.
   [[nodiscard]] std::vector<net::SchemefulSite> FetchSitesToClear(
@@ -172,6 +171,9 @@
   [[nodiscard]] bool MigrateToVersion3()
       VALID_CONTEXT_REQUIRED(sequence_checker_);
 
+  [[nodiscard]] bool MigrateToVersion4()
+      VALID_CONTEXT_REQUIRED(sequence_checker_);
+
   // Increase the `run_count` stored in the meta table by 1. Should only be
   // called once during DB initialization.  The value of `run_count` should
   // never be negative.
diff --git a/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc b/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc
index 1d0e241..f83c865 100644
--- a/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc
+++ b/content/browser/first_party_sets/database/first_party_sets_database_unittest.cc
@@ -38,7 +38,7 @@
 using ::testing::UnorderedElementsAre;
 
 // Version number of the database.
-const int kCurrentVersionNumber = 3;
+const int kCurrentVersionNumber = 4;
 
 static const size_t kTableCount = 7u;
 
@@ -117,9 +117,9 @@
     return size;
   }
 
-  size_t CountManualSetsEntries(sql::Database* db) {
+  size_t CountManualConfigurationsEntries(sql::Database* db) {
     size_t size = 0;
-    EXPECT_TRUE(sql::test::CountTableRows(db, "manual_sets", &size));
+    EXPECT_TRUE(sql::test::CountTableRows(db, "manual_configurations", &size));
     return size;
   }
 
@@ -157,7 +157,7 @@
   sql::Database db;
   EXPECT_TRUE(db.Open(db_path()));
   // [public_sets], [browser_context_sets_version], [policy_configurations],
-  // [manual_sets], [browser_context_sites_to_clear],
+  // [manual_configurations], [browser_context_sites_to_clear],
   // [browser_contexts_cleared], and [meta].
   EXPECT_EQ(kTableCount, sql::test::CountSQLTables(&db));
   EXPECT_EQ(kCurrentVersionNumber, VersionFromMetaTable(db));
@@ -181,7 +181,7 @@
   EXPECT_EQ(0u, CountBrowserContextSitesToClearEntries(&db));
   EXPECT_EQ(0u, CountBrowserContextsClearedEntries(&db));
   EXPECT_EQ(0u, CountPolicyConfigurationsEntries(&db));
-  EXPECT_EQ(0u, CountManualSetsEntries(&db));
+  EXPECT_EQ(0u, CountManualConfigurationsEntries(&db));
 }
 
 TEST_F(FirstPartySetsDatabaseTest, LoadDBFile_CurrentVersion_Success) {
@@ -203,7 +203,7 @@
   EXPECT_EQ(2u, CountBrowserContextSitesToClearEntries(&db));
   EXPECT_EQ(1u, CountBrowserContextsClearedEntries(&db));
   EXPECT_EQ(2u, CountPolicyConfigurationsEntries(&db));
-  EXPECT_EQ(2u, CountManualSetsEntries(&db));
+  EXPECT_EQ(2u, CountManualConfigurationsEntries(&db));
 
   histograms.ExpectUniqueSample("FirstPartySets.Database.InitStatus",
                                 FirstPartySetsDatabase::InitStatus::kSuccess,
@@ -232,7 +232,7 @@
   EXPECT_EQ(1u, CountBrowserContextSitesToClearEntries(&db));
   EXPECT_EQ(0u, CountBrowserContextsClearedEntries(&db));
   EXPECT_EQ(0u, CountPolicyConfigurationsEntries(&db));
-  EXPECT_EQ(0u, CountManualSetsEntries(&db));
+  EXPECT_EQ(0u, CountManualConfigurationsEntries(&db));
 
   histograms.ExpectUniqueSample("FirstPartySets.Database.InitStatus",
                                 FirstPartySetsDatabase::InitStatus::kSuccess,
@@ -261,7 +261,7 @@
   EXPECT_EQ(1u, CountBrowserContextSitesToClearEntries(&db));
   EXPECT_EQ(0u, CountBrowserContextsClearedEntries(&db));
   EXPECT_EQ(0u, CountPolicyConfigurationsEntries(&db));
-  EXPECT_EQ(0u, CountManualSetsEntries(&db));
+  EXPECT_EQ(0u, CountManualConfigurationsEntries(&db));
 
   histograms.ExpectUniqueSample("FirstPartySets.Database.InitStatus",
                                 FirstPartySetsDatabase::InitStatus::kSuccess,
@@ -333,6 +333,7 @@
   sql::Database db;
   EXPECT_TRUE(db.Open(db_path()));
   EXPECT_EQ(2u, CountPublicSetsEntries(&db));
+  EXPECT_EQ(2u, CountManualConfigurationsEntries(&db));
   EXPECT_EQ(2u, CountPolicyConfigurationsEntries(&db));
 
   // ============ Verify persisting public sets
@@ -379,9 +380,9 @@
 
   EXPECT_FALSE(s_config.Step());
 
-  // ============ Verify persisting manual sets
+  // ============ Verify persisting manual config
   const char kSelectManualSql[] =
-      "SELECT site,primary_site,site_type FROM manual_sets";
+      "SELECT site,primary_site,site_type FROM manual_configurations";
   sql::Statement s_manual(db.GetUniqueStatement(kSelectManualSql));
   EXPECT_TRUE(s_manual.Step());
   EXPECT_EQ(manual_site, s_manual.ColumnString(0));
@@ -444,7 +445,7 @@
   sql::Database db;
   EXPECT_TRUE(db.Open(db_path()));
   EXPECT_EQ(0u, CountPublicSetsEntries(&db));
-  EXPECT_EQ(2u, CountManualSetsEntries(&db));
+  EXPECT_EQ(2u, CountManualConfigurationsEntries(&db));
   EXPECT_EQ(2u, CountPolicyConfigurationsEntries(&db));
 
   // ============ Verify persisting context config
@@ -463,9 +464,9 @@
 
   EXPECT_FALSE(s_config.Step());
 
-  // ============ Verify persisting manual sets
+  // ============ Verify persisting manual configurations
   const char kSelectManualSql[] =
-      "SELECT site,primary_site,site_type FROM manual_sets";
+      "SELECT site,primary_site,site_type FROM manual_configurations";
   sql::Statement s_manual(db.GetUniqueStatement(kSelectManualSql));
   EXPECT_TRUE(s_manual.Step());
   EXPECT_EQ(manual_site, s_manual.ColumnString(0));
@@ -526,22 +527,22 @@
 
     EXPECT_FALSE(s_config.Step());
 
-    // Verify data in the manual_sets table
+    // Verify data in the manual_configurations table
     static constexpr char kSelectManualSetsSql[] =
         "SELECT browser_context_id,site,primary_site,site_type FROM "
-        "manual_sets";
-    sql::Statement s_manual_sets(db.GetUniqueStatement(kSelectManualSetsSql));
-    ASSERT_TRUE(s_manual_sets.Step());
-    ASSERT_EQ("b0", s_manual_sets.ColumnString(0));
-    ASSERT_EQ("https://ccc.test", s_manual_sets.ColumnString(1));
-    ASSERT_EQ("https://ddd.test", s_manual_sets.ColumnString(2));
-    ASSERT_EQ(1, s_manual_sets.ColumnInt(3));
+        "manual_configurations";
+    sql::Statement s_manual(db.GetUniqueStatement(kSelectManualSetsSql));
+    ASSERT_TRUE(s_manual.Step());
+    ASSERT_EQ("b0", s_manual.ColumnString(0));
+    ASSERT_EQ("https://ccc.test", s_manual.ColumnString(1));
+    ASSERT_EQ("https://ddd.test", s_manual.ColumnString(2));
+    ASSERT_EQ(1, s_manual.ColumnInt(3));
 
-    ASSERT_TRUE(s_manual_sets.Step());
-    ASSERT_EQ("b0", s_manual_sets.ColumnString(0));
-    ASSERT_EQ("https://ddd.test", s_manual_sets.ColumnString(1));
-    ASSERT_EQ("https://ddd.test", s_manual_sets.ColumnString(2));
-    ASSERT_EQ(0, s_manual_sets.ColumnInt(3));
+    ASSERT_TRUE(s_manual.Step());
+    ASSERT_EQ("b0", s_manual.ColumnString(0));
+    ASSERT_EQ("https://ddd.test", s_manual.ColumnString(1));
+    ASSERT_EQ("https://ddd.test", s_manual.ColumnString(2));
+    ASSERT_EQ(0, s_manual.ColumnInt(3));
   }
   const base::Version version("0.0.2");
   const std::string site = "https://site1.test";
@@ -637,23 +638,23 @@
   EXPECT_EQ("", s_config.ColumnString(2));
   EXPECT_FALSE(s_config.Step());
 
-  // ============ Verify new manual sets overwrote pre-existing data
+  // ============ Verify new manual config overwrote pre-existing data
   static constexpr char kSelectManualSetsSql[] =
-      "SELECT site,primary_site,site_type FROM manual_sets "
+      "SELECT site,primary_site,site_type FROM manual_configurations "
       "WHERE browser_context_id=?";
-  sql::Statement s_manual_sets(db.GetUniqueStatement(kSelectManualSetsSql));
-  s_manual_sets.BindString(0, browser_context_id);
-  EXPECT_TRUE(s_manual_sets.Step());
-  EXPECT_EQ(manual_site, s_manual_sets.ColumnString(0));
-  EXPECT_EQ(manual_primary, s_manual_sets.ColumnString(1));
-  EXPECT_EQ(1, s_manual_sets.ColumnInt(2));
+  sql::Statement s_manual(db.GetUniqueStatement(kSelectManualSetsSql));
+  s_manual.BindString(0, browser_context_id);
+  EXPECT_TRUE(s_manual.Step());
+  EXPECT_EQ(manual_site, s_manual.ColumnString(0));
+  EXPECT_EQ(manual_primary, s_manual.ColumnString(1));
+  EXPECT_EQ(1, s_manual.ColumnInt(2));
 
-  EXPECT_TRUE(s_manual_sets.Step());
-  EXPECT_EQ(manual_primary, s_manual_sets.ColumnString(0));
-  EXPECT_EQ(manual_primary, s_manual_sets.ColumnString(1));
-  EXPECT_EQ(0, s_manual_sets.ColumnInt(2));
+  EXPECT_TRUE(s_manual.Step());
+  EXPECT_EQ(manual_primary, s_manual.ColumnString(0));
+  EXPECT_EQ(manual_primary, s_manual.ColumnString(1));
+  EXPECT_EQ(0, s_manual.ColumnInt(2));
 
-  EXPECT_FALSE(s_manual_sets.Step());
+  EXPECT_FALSE(s_manual.Step());
 }
 
 TEST_F(FirstPartySetsDatabaseTest, PersistSets_PreExistingVersion) {
@@ -1177,9 +1178,44 @@
 
     // Check that expected tables are present.
     EXPECT_TRUE(db.DoesTableExist("policy_configurations"));
+    EXPECT_FALSE(db.DoesTableExist("policy_modifications"));
+    EXPECT_TRUE(db.DoesTableExist("manual_configurations"));
+    EXPECT_FALSE(db.DoesTableExist("manual_sets"));
 
     // Verify that data is preserved across the migration.
     EXPECT_EQ(2u, CountPolicyConfigurationsEntries(&db));
+    EXPECT_EQ(2u, CountManualConfigurationsEntries(&db));
+  }
+}
+
+TEST_F(FirstPartySetsDatabaseMigrationsTest, MigrateVersion3ToCurrent) {
+  ASSERT_TRUE(
+      sql::test::CreateDatabaseFromSQL(db_path(), GetSqlFilePath("v3.sql")));
+
+  // Verify pre-conditions.
+  {
+    sql::Database db;
+    ASSERT_TRUE(db.Open(db_path()));
+
+    ASSERT_EQ(3, VersionFromDatabase(&db));
+  }
+
+  MigrateDatabase();
+
+  // Verify schema is current.
+  {
+    sql::Database db;
+    ASSERT_TRUE(db.Open(db_path()));
+
+    // Check version.
+    EXPECT_EQ(kCurrentVersionNumber, VersionFromDatabase(&db));
+
+    // Check that expected tables are present.
+    EXPECT_TRUE(db.DoesTableExist("manual_configurations"));
+    EXPECT_FALSE(db.DoesTableExist("manual_sets"));
+
+    // Verify that data is preserved across the migration.
+    EXPECT_EQ(2u, CountManualConfigurationsEntries(&db));
   }
 }
 
diff --git a/content/browser/renderer_host/render_frame_host_android.cc b/content/browser/renderer_host/render_frame_host_android.cc
index d5fa543..23df34c 100644
--- a/content/browser/renderer_host/render_frame_host_android.cc
+++ b/content/browser/renderer_host/render_frame_host_android.cc
@@ -240,4 +240,12 @@
   return static_cast<jint>(render_frame_host_->GetLifecycleState());
 }
 
+void RenderFrameHostAndroid::InsertVisualStateCallback(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jcallback) {
+  render_frame_host()->InsertVisualStateCallback(
+      base::BindOnce(&base::android::RunBooleanCallbackAndroid,
+                     base::android::ScopedJavaGlobalRef<jobject>(jcallback)));
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_android.h b/content/browser/renderer_host/render_frame_host_android.h
index d2a7b9b..d2435115 100644
--- a/content/browser/renderer_host/render_frame_host_android.h
+++ b/content/browser/renderer_host/render_frame_host_android.h
@@ -100,6 +100,10 @@
   jint GetLifecycleState(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>&) const;
 
+  void InsertVisualStateCallback(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcallback);
+
   RenderFrameHostImpl* render_frame_host() const { return render_frame_host_; }
 
  private:
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 8e22907..149786f9 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -8664,6 +8664,7 @@
   DCHECK(!blink::IsRendererDebugURL(common_params->url));
   DCHECK(navigation_request);
   DCHECK_EQ(this, navigation_request->GetRenderFrameHost());
+  AssertBrowserContextShutdownHasntStarted();
 
   bool is_same_document =
       NavigationTypeUtils::IsSameDocument(common_params->navigation_type);
@@ -8940,10 +8941,13 @@
             &non_network_factories);
 
     for (auto& factory : non_network_factories) {
-      // TODO(https://crbug.com/1376879): Remove the ad-hoc debugging code after
-      // the bug is understood and/or fixed.
       const std::string& scheme = factory.first;
-      SCOPED_CRASH_KEY_STRING32("non_network_factories", "scheme", scheme);
+      mojo::PendingRemote<network::mojom::URLLoaderFactory>
+          original_pending_factory = std::move(factory.second);
+      // TODO(https://crbug.com/1376879): Remove the workaround below once the
+      // root cause of the bug has been fixed.
+      if (!original_pending_factory)
+        continue;
 
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           pending_factory_proxy;
@@ -8952,8 +8956,9 @@
       WillCreateURLLoaderFactory(
           subresource_loader_factories_config.origin(), &factory_receiver,
           subresource_loader_factories_config.ukm_source_id());
+
       mojo::Remote<network::mojom::URLLoaderFactory> remote(
-          std::move(factory.second));
+          std::move(original_pending_factory));
       remote->Clone(std::move(factory_receiver));
       subresource_loader_factories->pending_scheme_specific_factories().emplace(
           scheme, std::move(pending_factory_proxy));
@@ -14006,13 +14011,24 @@
 }
 
 void RenderFrameHostImpl::AssertNonSpeculativeFrame() const {
-  if (lifecycle_state() != LifecycleStateImpl::kSpeculative)
+  if (LIKELY(lifecycle_state() != LifecycleStateImpl::kSpeculative))
     return;
 
   NOTREACHED();
   base::debug::DumpWithoutCrashing();
 }
 
+void RenderFrameHostImpl::AssertBrowserContextShutdownHasntStarted() {
+  if (LIKELY(!GetBrowserContext()->ShutdownStarted()))
+    return;
+
+  NOTREACHED() << "BrowserContext->ShutdownStarted() without first closing all "
+                  "WebContents";
+  SCOPED_CRASH_KEY_STRING256("shutdown", "frame->ToDebugString",
+                             ToDebugString());
+  base::debug::DumpWithoutCrashing();
+}
+
 blink::StorageKey RenderFrameHostImpl::GetBucketStorageKey() {
   return storage_key_;
 }
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index dc3c86a4..7b3be29 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -3587,6 +3587,13 @@
   // JavaScriptExecuteRequestInIsolatedWorld.
   void AssertNonSpeculativeFrame() const;
 
+  // Asserts that the BrowserContext (e.g. Profile in the //chrome layer) of
+  // this frame hasn't started shutting down.  The owner of the BrowserContext
+  // is responsible for closing all WebContents before initiating destruction of
+  // the BrowserContext (and closing the WebContents should destroy all the
+  // associated RenderFrameHostImpl objects).
+  void AssertBrowserContextShutdownHasntStarted();
+
   // A feature that blocks back/forward cache is used. Count the usage and evict
   // the entry if necessary.
   void OnBackForwardCacheDisablingFeatureUsed(
diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc
index 6858566..0c6a78a 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -149,4 +149,8 @@
   return false;
 }
 
+int RenderWidgetHostDelegate::GetVirtualKeyboardResizeHeight() {
+  return 0;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h
index 5f1eea55..780b2014 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -314,6 +314,11 @@
                                  const gfx::Rect& initial_anchor_rect_in_dips) {
   }
 
+  // Returns the amount that this view has been resized by a showing virtual
+  // keyboard or 0 if the virtual keyboard is hidden or in a mode that doesn't
+  // resize the view.
+  virtual int GetVirtualKeyboardResizeHeight();
+
  protected:
   virtual ~RenderWidgetHostDelegate() {}
 };
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 5a5a4f6..0e38398 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1094,6 +1094,8 @@
         gfx::Rect(view_->GetCompositorViewportPixelSize());
     visual_properties.window_controls_overlay_rect =
         delegate_->GetWindowsControlsOverlayRect();
+    visual_properties.virtual_keyboard_resize_height_physical_px =
+        delegate_->GetVirtualKeyboardResizeHeight();
   } else {
     visual_properties.compositor_viewport_pixel_rect =
         properties_from_parent_local_root_.compositor_viewport;
diff --git a/content/browser/resources/attribution_reporting/attribution_internals.ts b/content/browser/resources/attribution_reporting/attribution_internals.ts
index 308c32e..3e8f19e 100644
--- a/content/browser/resources/attribution_reporting/attribution_internals.ts
+++ b/content/browser/resources/attribution_reporting/attribution_internals.ts
@@ -254,6 +254,7 @@
   status: string;
   aggregatableBudgetConsumed: bigint;
   aggregatableDedupKeys: string;
+  debugReportingEnabled: boolean;
 
   constructor(mojo: WebUISource) {
     this.sourceEventId = mojo.sourceEventId;
@@ -272,6 +273,7 @@
     this.aggregatableBudgetConsumed = mojo.aggregatableBudgetConsumed;
     this.aggregatableDedupKeys = mojo.aggregatableDedupKeys.join(', ');
     this.status = attributabilityToText(mojo.attributability);
+    this.debugReportingEnabled = mojo.debugReportingEnabled;
   }
 }
 
@@ -303,6 +305,9 @@
       new ValueColumn<Source, string>('Dedup Keys', (e) => e.dedupKeys),
       new ValueColumn<Source, string>(
           'Aggregatable Dedup Keys', (e) => e.aggregatableDedupKeys),
+      new ValueColumn<Source, string>(
+          'Verbose Debug Reporting',
+          (e) => e.debugReportingEnabled ? 'enabled' : 'disabled'),
     ];
 
     this.emptyRowText = 'No sources.';
@@ -351,6 +356,7 @@
   aggregatableTriggers: string;
   aggregatableValues: string;
   aggregatableDedupKey: string;
+  debugReportingEnabled: boolean;
 
   constructor(mojo: WebUITrigger) {
     this.triggerTime = new Date(mojo.triggerTime);
@@ -400,6 +406,7 @@
 
     this.eventLevelStatus = triggerStatusToText(mojo.eventLevelStatus);
     this.aggregatableStatus = triggerStatusToText(mojo.aggregatableStatus);
+    this.debugReportingEnabled = mojo.debugReportingEnabled;
   }
 }
 
@@ -428,6 +435,9 @@
           'Aggregatable Values', (e) => e.aggregatableValues),
       new ValueColumn<Trigger, string>(
           'Aggregatable Dedup Key', (e) => e.aggregatableDedupKey),
+      new ValueColumn<Trigger, string>(
+          'Verbose Debug Reporting',
+          (e) => e.debugReportingEnabled ? 'enabled' : 'disabled'),
     ];
 
     this.emptyRowText = 'No triggers.';
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 58e9c1d..c1736cb 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -174,6 +174,7 @@
 #include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/accessibility/ax_tree_combiner.h"
+#include "ui/base/ime/mojom/virtual_keyboard_types.mojom.h"
 #include "ui/base/pointer/pointer_device.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/color/color_provider_manager.h"
@@ -2231,6 +2232,26 @@
       &WebContentsObserver::DidChangeVerticalScrollDirection, scroll_direction);
 }
 
+int WebContentsImpl::GetVirtualKeyboardResizeHeight() {
+  // Only consider a web contents to be insetted by the virtual keyboard if it
+  // is in the currently active tab.
+  if (GetVisibility() != Visibility::VISIBLE)
+    return 0;
+
+  // The only mode where the virtual keyboard causes the web contents to be
+  // resized is kResizesContent.
+  if (GetPrimaryPage().virtual_keyboard_mode() !=
+      ui::mojom::VirtualKeyboardMode::kResizesContent) {
+    return 0;
+  }
+
+  // The virtual keyboard never resizes content when fullscreened.
+  if (IsFullscreen())
+    return 0;
+
+  return GetDelegate() ? GetDelegate()->GetVirtualKeyboardHeight(this) : 0;
+}
+
 void WebContentsImpl::OnAudioStateChanged() {
   // This notification can come from any embedded contents or from this
   // WebContents' stream monitor. Aggregate these signals to get the actual
@@ -2839,6 +2860,9 @@
   // GuestViews in the same StoragePartition need to find each other's frames.
   prefs.renderer_wide_named_frame_lookup = IsGuest();
 
+  if (command_line.HasSwitch(switches::kHideScrollbars))
+    prefs.hide_scrollbars = true;
+
   GetContentClient()->browser()->OverrideWebkitPrefs(this, &prefs);
   return prefs;
 }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index c12caff..93244e9 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -914,6 +914,7 @@
                              const gfx::Size& new_size) override;
   void OnVerticalScrollDirectionChanged(
       viz::VerticalScrollDirection scroll_direction) override;
+  int GetVirtualKeyboardResizeHeight() override;
 
   double GetPendingPageZoomLevel() override;
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java b/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
index 9bf8b96..f6a14b8 100644
--- a/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/framehost/RenderFrameHostImpl.java
@@ -228,6 +228,15 @@
                 mNativeRenderFrameHostAndroid, RenderFrameHostImpl.this);
     }
 
+    @Override
+    public void insertVisualStateCallback(Callback<Boolean> callback) {
+        if (mNativeRenderFrameHostAndroid == 0) {
+            callback.onResult(false);
+        }
+        RenderFrameHostImplJni.get().insertVisualStateCallback(
+                mNativeRenderFrameHostAndroid, callback);
+    }
+
     @NativeMethods
     interface Natives {
         GURL getLastCommittedURL(long nativeRenderFrameHostAndroid, RenderFrameHostImpl caller);
@@ -258,5 +267,7 @@
                 RenderFrameHostImpl caller, String relyingPartyId, Origin effectiveOrigin,
                 boolean isPaymentCredentialCreation);
         int getLifecycleState(long nativeRenderFrameHostAndroid, RenderFrameHostImpl caller);
+        void insertVisualStateCallback(
+                long nativeRenderFrameHostAndroid, Callback<Boolean> callback);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java b/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
index d8510c4..466618b 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/RenderFrameHost.java
@@ -174,4 +174,21 @@
      */
     @LifecycleState
     int getLifecycleState();
+
+    /**
+     * Inserts a VisualStateCallback that's resolved once a visual update has been processed.
+     *
+     * The VisualStateCallback will be inserted in Blink and will be invoked when the contents of
+     * the DOM tree at the moment that the callback was inserted (or later) are submitted to the
+     * compositor in a CompositorFrame. In other words, the following events need to happen before
+     * the callback is invoked:
+     * 1. The DOM tree is committed becoming the pending tree - see ThreadProxy::BeginMainFrame
+     * 2. The pending tree is activated becoming the active tree
+     * 3. The compositor calls Draw and submits a new CompositorFrame to the Viz process.
+     * The callback is synchronously invoked if this is called while being destroyed.
+     *
+     * @param callback the callback to be inserted. The callback takes a single Boolean parameter
+     *     which will be true if the visual state update was successful or false if it was aborted.
+     */
+    void insertVisualStateCallback(Callback<Boolean> callback);
 }
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index ffb1fc98..39eadbc 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -853,6 +853,8 @@
     kSource,
     kTrigger,
     kReport,
+    kSourceVerboseDebugReport,
+    kTriggerVerboseDebugReport,
     kAny,
   };
 
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 4f4ce7c4..7122abf 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -333,6 +333,10 @@
   return false;
 }
 
+int WebContentsDelegate::GetVirtualKeyboardHeight(WebContents* web_contents) {
+  return 0;
+}
+
 bool WebContentsDelegate::OnlyExpandTopControlsAtPageTop() {
   return false;
 }
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 03b810c5..e2ce097 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -651,6 +651,7 @@
   virtual int GetBottomControlsMinHeight();
   virtual bool ShouldAnimateBrowserControlsHeightChanges();
   virtual bool DoBrowserControlsShrinkRendererSize(WebContents* web_contents);
+  virtual int GetVirtualKeyboardHeight(WebContents* web_contents);
   // Returns true if the top controls should only expand at the top of the page,
   // so they'll only be visible if the page is scrolled to the top.
   virtual bool OnlyExpandTopControlsAtPageTop();
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 2d16cfa4a..38bbb62 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -498,6 +498,10 @@
 // Causes the GPU process to display a dialog on launch.
 const char kGpuStartupDialog[]              = "gpu-startup-dialog";
 
+// Prevents creating scrollbars for web content. Useful for taking consistent
+// screenshots.
+const char kHideScrollbars[] = "hide-scrollbars";
+
 // Run the GPU process as a thread in the browser process.
 const char kInProcessGPU[]                  = "in-process-gpu";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 2c202f8..f1395bf 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -154,6 +154,7 @@
 CONTENT_EXPORT extern const char kGpuProcess[];
 CONTENT_EXPORT extern const char kGpuSandboxStartEarly[];
 CONTENT_EXPORT extern const char kGpuStartupDialog[];
+extern const char kHideScrollbars[];
 CONTENT_EXPORT extern const char kInProcessGPU[];
 CONTENT_EXPORT extern const char kIPCConnectionTimeout[];
 CONTENT_EXPORT extern const char kIsolatedAppOrigins[];
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
index bf8eacf..e6efdfc 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockRenderFrameHost.java
@@ -98,4 +98,7 @@
     public int getLifecycleState() {
         return LifecycleState.ACTIVE;
     }
+
+    @Override
+    public void insertVisualStateCallback(Callback<Boolean> callback) {}
 }
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/Coordinates.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/Coordinates.java
index 88f68f4..62660f8 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/Coordinates.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/util/Coordinates.java
@@ -54,4 +54,8 @@
     public int getContentHeightPixInt() {
         return mRenderCoordinates.getContentHeightPixInt();
     }
+
+    public float getContentOffsetYPix() {
+        return mRenderCoordinates.getContentOffsetYPix();
+    }
 }
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 39d45cc..99a8fef 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -820,10 +820,8 @@
 #endif  // BUILDFLAG(IS_POSIX)
 
   {
-    // This can be called from a posted task. Allow nested tasks here, because
-    // otherwise the test body will have to do it in order to use RunLoop for
-    // waiting.
-    base::CurrentThread::ScopedNestableTaskAllower allow;
+    // This shouldn't be invoked from a posted task.
+    DCHECK(!base::RunLoop::IsRunningOnCurrentThread());
 
 #if !BUILDFLAG(IS_ANDROID)
     // Fail the test if a renderer crashes while the test is running.
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index 0de8125..00f2af4 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -566,7 +566,6 @@
       return true;
 
     case ax::mojom::Event::kAriaAttributeChanged:
-    case ax::mojom::Event::kChildrenChanged:
     case ax::mojom::Event::kDocumentTitleChanged:
     case ax::mojom::Event::kExpandedChanged:
     case ax::mojom::Event::kHide:
@@ -588,6 +587,7 @@
     // This list is duplicated in WebFrameTestProxy::PostAccessibilityEvent().
     case ax::mojom::Event::kAlert:
     case ax::mojom::Event::kAutocorrectionOccured:
+    case ax::mojom::Event::kChildrenChanged:
     case ax::mojom::Event::kControlsChanged:
     case ax::mojom::Event::kEndOfTest:
     case ax::mojom::Event::kFocusAfterMenuClose:
@@ -761,7 +761,7 @@
   if (obj.IsNull())
     return;
 
-  HandleAXEvent(ui::AXEvent(obj.AxID(), ax::mojom::Event::kChildrenChanged));
+  MarkWebAXObjectDirty(obj, /* subtree */ false);
 }
 
 void RenderAccessibilityImpl::ShowPluginContextMenu() {
diff --git a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
index 5b0530c..65e50085 100644
--- a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
+++ b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
@@ -453,8 +453,7 @@
 
   // Send a childrenChanged on "A".
   ClearHandledUpdates();
-  GetRenderAccessibilityImpl()->HandleAXEvent(
-      ui::AXEvent(node_a.AxID(), ax::mojom::Event::kChildrenChanged));
+  GetRenderAccessibilityImpl()->MarkWebAXObjectDirty(node_a, false);
 
   // Hide node "B" ("C" stays visible).
   ExecuteJavaScriptForTests(
@@ -466,7 +465,7 @@
 
   // Since ignored nodes are included in the ax tree with State::kIgnored set,
   // "C" is NOT reparented, only the changed nodes are re-serialized.
-  // "A" updates because it handled Event::kChildrenChanged
+  // "A" updates because it handled dirty object
   // "B" updates because its State::kIgnored has changed
   EXPECT_EQ(0, update.node_id_to_clear);
   EXPECT_EQ(node_a.AxID(), update.nodes[0].id);
@@ -502,8 +501,7 @@
   WebAXObject node_c = node_b.ChildAt(0);
 
   // Send a childrenChanged on "A" and show node "B",
-  GetRenderAccessibilityImpl()->HandleAXEvent(
-      ui::AXEvent(node_a.AxID(), ax::mojom::Event::kChildrenChanged));
+  GetRenderAccessibilityImpl()->MarkWebAXObjectDirty(node_a, false);
   ExecuteJavaScriptForTests(
       "document.getElementById('B').style.visibility = 'visible';");
 
@@ -514,7 +512,7 @@
 
   // Since ignored nodes are included in the ax tree with State::kIgnored set,
   // "C" is NOT reparented, only the changed nodes are re-serialized.
-  // "A" updates because it handled Event::kChildrenChanged
+  // "A" updates because it handled the dirty
   // "B" updates because its State::kIgnored has changed
   ASSERT_EQ(2U, update.nodes.size());
   EXPECT_EQ(0, update.node_id_to_clear);
@@ -1220,8 +1218,7 @@
   // No URL-keyed metrics should be fired after we send one event.
   WebDocument document = GetMainFrame()->GetDocument();
   WebAXObject root_obj = WebAXObject::FromWebDocument(document);
-  GetRenderAccessibilityImpl()->HandleAXEvent(
-      ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kChildrenChanged));
+  GetRenderAccessibilityImpl()->MarkWebAXObjectDirty(root_obj, false);
   SendPendingAccessibilityEvents();
   EXPECT_EQ(0, ukm_recorder()->calls());
   histogram_tester.ExpectTotalCount(
@@ -1230,8 +1227,7 @@
   // No URL-keyed metrics should be fired even after an event that takes
   // 300 ms, but we should now have something to send.
   // This must be >= kMinSerializationTimeToSendInMS
-  GetRenderAccessibilityImpl()->HandleAXEvent(
-      ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kChildrenChanged));
+  GetRenderAccessibilityImpl()->MarkWebAXObjectDirty(root_obj, false);
   SendPendingAccessibilityEvents();
   SetTimeDelayForNextSerialize(base::Milliseconds(300));
   EXPECT_EQ(0, ukm_recorder()->calls());
@@ -1241,8 +1237,7 @@
   // After 1000 seconds have passed, the next time we send an event we should
   // send URL-keyed metrics.
   task_environment_.FastForwardBy(base::Seconds(1000));
-  GetRenderAccessibilityImpl()->HandleAXEvent(
-      ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kChildrenChanged));
+  GetRenderAccessibilityImpl()->MarkWebAXObjectDirty(root_obj, false);
   SendPendingAccessibilityEvents();
   EXPECT_EQ(1, ukm_recorder()->calls());
   histogram_tester.ExpectTotalCount(
@@ -1251,8 +1246,7 @@
   // Send another event that takes a long (simulated) time to serialize.
   // This must be >= kMinSerializationTimeToSend
   SetTimeDelayForNextSerialize(base::Milliseconds(200));
-  GetRenderAccessibilityImpl()->HandleAXEvent(
-      ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kChildrenChanged));
+  GetRenderAccessibilityImpl()->MarkWebAXObjectDirty(root_obj, false);
   SendPendingAccessibilityEvents();
   histogram_tester.ExpectTotalCount(
       "Accessibility.Performance.SendPendingAccessibilityEvents", 4);
diff --git a/content/services/auction_worklet/auction_v8_devtools_agent.cc b/content/services/auction_worklet/auction_v8_devtools_agent.cc
index e5b428f..e028ee9 100644
--- a/content/services/auction_worklet/auction_v8_devtools_agent.cc
+++ b/content/services/auction_worklet/auction_v8_devtools_agent.cc
@@ -68,7 +68,8 @@
     blink::mojom::DevToolsSessionStatePtr reattach_session_state,
     bool client_expects_binary_responses,
     bool client_is_trusted,
-    const std::string& session_id) {
+    const std::string& session_id,
+    bool session_waits_for_debugger) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_);
   int context_group_id = receivers_.current_context();
   ContextGroupInfo& context_group_info = context_groups_[context_group_id];
@@ -81,9 +82,9 @@
           base::Unretained(this));
   auto session_impl = std::make_unique<AuctionV8DevToolsSession>(
       v8_helper_, debug_command_queue_, context_group_id, session_id,
-      client_expects_binary_responses, std::move(host),
-      io_session_receiver_sequence_, std::move(io_session_receiver),
-      std::move(session_destroyed));
+      client_expects_binary_responses, session_waits_for_debugger,
+      std::move(host), io_session_receiver_sequence_,
+      std::move(io_session_receiver), std::move(session_destroyed));
   context_group_info.sessions.insert(session_impl.get());
   sessions_.Add(std::move(session_impl), std::move(session_receiver));
 }
diff --git a/content/services/auction_worklet/auction_v8_devtools_agent.h b/content/services/auction_worklet/auction_v8_devtools_agent.h
index 4d1e146..f64916e3 100644
--- a/content/services/auction_worklet/auction_v8_devtools_agent.h
+++ b/content/services/auction_worklet/auction_v8_devtools_agent.h
@@ -106,7 +106,8 @@
       blink::mojom::DevToolsSessionStatePtr reattach_session_state,
       bool client_expects_binary_responses,
       bool client_is_trusted,
-      const std::string& session_id) override;
+      const std::string& session_id,
+      bool session_waits_for_debugger) override;
   void InspectElement(const ::gfx::Point& point) override;
   void ReportChildTargets(bool report,
                           bool wait_for_debugger,
diff --git a/content/services/auction_worklet/auction_v8_devtools_session.cc b/content/services/auction_worklet/auction_v8_devtools_session.cc
index d21b7f19..3fe57f3 100644
--- a/content/services/auction_worklet/auction_v8_devtools_session.cc
+++ b/content/services/auction_worklet/auction_v8_devtools_session.cc
@@ -157,6 +157,7 @@
     int context_group_id,
     const std::string& session_id,
     bool client_expects_binary_responses,
+    bool session_waits_for_debugger,
     mojo::PendingAssociatedRemote<blink::mojom::DevToolsSessionHost> host,
     scoped_refptr<base::SequencedTaskRunner> io_session_receiver_sequence,
     mojo::PendingReceiver<blink::mojom::DevToolsSession> io_session_receiver,
@@ -171,7 +172,10 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(v8_sequence_checker_);
   v8_session_ = v8_helper_->inspector()->connect(
       context_group_id_, this /* as V8Inspector::Channel */,
-      v8_inspector::StringView(), v8_inspector::V8Inspector::kFullyTrusted);
+      v8_inspector::StringView(), v8_inspector::V8Inspector::kFullyTrusted,
+      session_waits_for_debugger
+          ? v8_inspector::V8Inspector::kWaitingForDebugger
+          : v8_inspector::V8Inspector::kNotWaitingForDebugger);
   IOSession::Create(
       std::move(io_session_receiver), std::move(io_session_receiver_sequence),
       debug_command_queue_,
diff --git a/content/services/auction_worklet/auction_v8_devtools_session.h b/content/services/auction_worklet/auction_v8_devtools_session.h
index c5ad11c..f33753be 100644
--- a/content/services/auction_worklet/auction_v8_devtools_session.h
+++ b/content/services/auction_worklet/auction_v8_devtools_session.h
@@ -56,6 +56,7 @@
       int context_group_id,
       const std::string& session_id,
       bool client_expects_binary_responses,
+      bool session_waits_for_debugger,
       mojo::PendingAssociatedRemote<blink::mojom::DevToolsSessionHost> host,
       scoped_refptr<base::SequencedTaskRunner> io_session_receiver_sequence,
       mojo::PendingReceiver<blink::mojom::DevToolsSession> io_session_receiver,
diff --git a/content/services/auction_worklet/worklet_devtools_debug_test_util.cc b/content/services/auction_worklet/worklet_devtools_debug_test_util.cc
index eb8db32..9cb2ab7 100644
--- a/content/services/auction_worklet/worklet_devtools_debug_test_util.cc
+++ b/content/services/auction_worklet/worklet_devtools_debug_test_util.cc
@@ -52,7 +52,8 @@
                                 session_.BindNewEndpointAndPassReceiver(),
                                 io_session_.BindNewPipeAndPassReceiver(),
                                 nullptr, use_binary_protocol_,
-                                /*client_is_trusted=*/true, session_id_);
+                                /*client_is_trusted=*/true, session_id_,
+                                /*session_waits_for_debugger=*/false);
 }
 
 TestDevToolsAgentClient::~TestDevToolsAgentClient() = default;
diff --git a/content/test/attribution_simulator_impl.cc b/content/test/attribution_simulator_impl.cc
index a8a10d0..634e573 100644
--- a/content/test/attribution_simulator_impl.cc
+++ b/content/test/attribution_simulator_impl.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/raw_ref.h"
 #include "content/public/test/attribution_simulator.h"
 
 #include <stddef.h>
@@ -16,6 +15,7 @@
 
 #include "base/bind.h"
 #include "base/check.h"
+#include "base/check_op.h"
 #include "base/files/file_path.h"
 #include "base/functional/overloaded.h"
 #include "base/guid.h"
@@ -115,10 +115,6 @@
         report_time_format(report_time_format),
         remove_assembled_report(remove_assembled_report),
         time_origin(time_origin) {}
-  AttributionReportJsonConverter(const AttributionReportJsonConverter&) =
-      delete;
-  AttributionReportJsonConverter& operator=(
-      const AttributionReportJsonConverter&) = delete;
 
   base::Value::Dict ToJson(
       const AttributionReport& report,
@@ -207,46 +203,23 @@
   const base::Time time_origin;
 };
 
-class SentReportAccumulator : public AttributionReportSender {
+class FakeReportSender : public AttributionReportSender {
  public:
-  SentReportAccumulator(base::Value::List& event_level_reports,
-                        base::Value::List& debug_event_level_reports,
-                        base::Value::List& aggregatable_reports,
-                        base::Value::List& debug_aggregatable_reports,
-                        const AttributionReportJsonConverter& json_converter)
-      : event_level_reports_(event_level_reports),
-        debug_event_level_reports_(debug_event_level_reports),
-        aggregatable_reports_(aggregatable_reports),
-        debug_aggregatable_reports_(debug_aggregatable_reports),
-        json_converter_(json_converter) {}
+  FakeReportSender() = default;
 
-  ~SentReportAccumulator() override = default;
+  ~FakeReportSender() override = default;
 
-  SentReportAccumulator(const SentReportAccumulator&) = delete;
-  SentReportAccumulator(SentReportAccumulator&&) = delete;
+  FakeReportSender(const FakeReportSender&) = delete;
+  FakeReportSender(FakeReportSender&&) = delete;
 
-  SentReportAccumulator& operator=(const SentReportAccumulator&) = delete;
-  SentReportAccumulator& operator=(SentReportAccumulator&&) = delete;
+  FakeReportSender& operator=(const FakeReportSender&) = delete;
+  FakeReportSender& operator=(FakeReportSender&&) = delete;
 
  private:
   // AttributionManagerImpl::ReportSender:
   void SendReport(AttributionReport report,
                   bool is_debug_report,
                   ReportSentCallback sent_callback) override {
-    base::Value::List* reports;
-    switch (report.GetReportType()) {
-      case AttributionReport::Type::kEventLevel:
-        reports = is_debug_report ? &*debug_event_level_reports_
-                                  : &*event_level_reports_;
-        break;
-      case AttributionReport::Type::kAggregatableAttribution:
-        reports = is_debug_report ? &*debug_aggregatable_reports_
-                                  : &*aggregatable_reports_;
-        break;
-    }
-
-    reports->Append(json_converter_->ToJson(report, is_debug_report));
-
     std::move(sent_callback)
         .Run(std::move(report), SendResult(SendResult::Status::kSent,
                                            /*http_response_code=*/200));
@@ -256,12 +229,6 @@
     // TODO(crbug.com/1371970): Consider supporting debug reports in the
     // simulator.
   }
-
-  const raw_ref<base::Value::List> event_level_reports_;
-  const raw_ref<base::Value::List> debug_event_level_reports_;
-  const raw_ref<base::Value::List> aggregatable_reports_;
-  const raw_ref<base::Value::List> debug_aggregatable_reports_;
-  const raw_ref<const AttributionReportJsonConverter> json_converter_;
 };
 
 // Registers sources and triggers in the `AttributionManagerImpl` and records
@@ -270,16 +237,10 @@
  public:
   AttributionEventHandler(AttributionManagerImpl* manager,
                           StoragePartitionImpl* storage_partition,
-                          const AttributionReportJsonConverter& json_converter,
-                          base::Value::List& rejected_sources,
-                          base::Value::List& rejected_triggers,
-                          base::Value::List& replaced_event_level_reports)
+                          AttributionReportJsonConverter json_converter)
       : manager_(manager),
         storage_partition_(storage_partition),
-        json_converter_(json_converter),
-        rejected_sources_(rejected_sources),
-        rejected_triggers_(rejected_triggers),
-        replaced_event_level_reports_(replaced_event_level_reports) {
+        json_converter_(json_converter) {
     DCHECK(manager_);
     DCHECK(storage_partition_);
 
@@ -350,6 +311,43 @@
                        /*delete_rate_limit_data=*/true, base::DoNothing()));
   }
 
+  base::Value::Dict TakeOutput() {
+    base::Value::Dict output;
+
+    if (!event_level_reports_.empty()) {
+      output.Set("event_level_reports",
+                 std::exchange(event_level_reports_, {}));
+    }
+
+    if (!debug_event_level_reports_.empty()) {
+      output.Set("debug_event_level_reports",
+                 std::exchange(debug_event_level_reports_, {}));
+    }
+
+    if (!aggregatable_reports_.empty()) {
+      output.Set("aggregatable_reports",
+                 std::exchange(aggregatable_reports_, {}));
+    }
+
+    if (!debug_aggregatable_reports_.empty()) {
+      output.Set("debug_aggregatable_reports",
+                 std::exchange(debug_aggregatable_reports_, {}));
+    }
+
+    if (!rejected_sources_.empty())
+      output.Set("rejected_sources", std::exchange(rejected_sources_, {}));
+
+    if (!rejected_triggers_.empty())
+      output.Set("rejected_triggers", std::exchange(rejected_triggers_, {}));
+
+    if (!replaced_event_level_reports_.empty()) {
+      output.Set("replaced_event_level_reports",
+                 std::exchange(replaced_event_level_reports_, {}));
+    }
+
+    return output;
+  }
+
  private:
   void FlushCookies() {
     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
@@ -388,7 +386,7 @@
     dict.Set("reason", reason.str());
     dict.Set("source", std::move(input_value));
 
-    rejected_sources_->Append(std::move(dict));
+    rejected_sources_.Append(std::move(dict));
   }
 
   void OnTriggerHandled(const AttributionTrigger& trigger,
@@ -403,7 +401,7 @@
       case AttributionTrigger::EventLevelResult::kSuccess:
         break;
       case AttributionTrigger::EventLevelResult::kSuccessDroppedLowerPriority:
-        replaced_event_level_reports_->Append(json_converter_->ToJson(
+        replaced_event_level_reports_.Append(json_converter_.ToJson(
             *result.replaced_event_level_report(),
             /*is_debug_report=*/false,
             result.new_event_level_report()->external_report_id()));
@@ -463,7 +461,27 @@
 
     dict.Set("trigger", std::move(input_value));
 
-    rejected_triggers_->Append(std::move(dict));
+    rejected_triggers_.Append(std::move(dict));
+  }
+
+  void OnReportSent(const AttributionReport& report,
+                    bool is_debug_report,
+                    const SendResult& info) override {
+    DCHECK_EQ(info.status, SendResult::Status::kSent);
+
+    base::Value::List* reports;
+    switch (report.GetReportType()) {
+      case AttributionReport::Type::kEventLevel:
+        reports = is_debug_report ? &debug_event_level_reports_
+                                  : &event_level_reports_;
+        break;
+      case AttributionReport::Type::kAggregatableAttribution:
+        reports = is_debug_report ? &debug_aggregatable_reports_
+                                  : &aggregatable_reports_;
+        break;
+    }
+
+    reports->Append(json_converter_.ToJson(report, is_debug_report));
   }
 
   base::ScopedObservation<AttributionManagerImpl, AttributionObserver>
@@ -471,11 +489,17 @@
 
   const base::raw_ptr<AttributionManagerImpl> manager_;
   const base::raw_ptr<StoragePartitionImpl> storage_partition_;
-  const raw_ref<const AttributionReportJsonConverter> json_converter_;
 
-  const raw_ref<base::Value::List> rejected_sources_;
-  const raw_ref<base::Value::List> rejected_triggers_;
-  const raw_ref<base::Value::List> replaced_event_level_reports_;
+  const AttributionReportJsonConverter json_converter_;
+
+  base::Value::List rejected_sources_;
+  base::Value::List rejected_triggers_;
+  base::Value::List replaced_event_level_reports_;
+
+  base::Value::List event_level_reports_;
+  base::Value::List debug_event_level_reports_;
+  base::Value::List aggregatable_reports_;
+  base::Value::List debug_aggregatable_reports_;
 
   base::circular_deque<base::Value> input_values_;
 };
@@ -512,15 +536,6 @@
     rng = std::make_unique<AttributionDefaultRandomGenerator>();
   }
 
-  const AttributionReportJsonConverter json_converter(
-      options.remove_report_ids, options.report_time_format,
-      options.remove_assembled_report, time_origin);
-
-  base::Value::List event_level_reports;
-  base::Value::List debug_event_level_reports;
-  base::Value::List aggregatable_reports;
-  base::Value::List debug_aggregatable_reports;
-
   auto* storage_partition = static_cast<StoragePartitionImpl*>(
       browser_context.GetDefaultStoragePartition());
 
@@ -540,18 +555,14 @@
       AttributionStorageDelegateImpl::CreateForTesting(
           options.noise_mode, options.delay_mode, options.config,
           std::move(rng)),
-      std::move(cookie_checker),
-      std::make_unique<SentReportAccumulator>(
-          event_level_reports, debug_event_level_reports, aggregatable_reports,
-          debug_aggregatable_reports, json_converter),
+      std::move(cookie_checker), std::make_unique<FakeReportSender>(),
       storage_partition);
 
-  base::Value::List rejected_sources;
-  base::Value::List rejected_triggers;
-  base::Value::List replaced_event_level_reports;
   AttributionEventHandler handler(
-      manager.get(), storage_partition, json_converter, rejected_sources,
-      rejected_triggers, replaced_event_level_reports);
+      manager.get(), storage_partition,
+      AttributionReportJsonConverter(
+          options.remove_report_ids, options.report_time_format,
+          options.remove_assembled_report, time_origin));
 
   static_cast<AggregationServiceImpl*>(
       storage_partition->GetAggregationService())
@@ -585,36 +596,7 @@
     task_environment.FastForwardBy(last_report_time - base::Time::Now());
   }
 
-  base::Value::Dict output;
-
-  if (!event_level_reports.empty())
-    output.Set("event_level_reports", std::move(event_level_reports));
-
-  if (!debug_event_level_reports.empty()) {
-    output.Set("debug_event_level_reports",
-               std::move(debug_event_level_reports));
-  }
-
-  if (!aggregatable_reports.empty())
-    output.Set("aggregatable_reports", std::move(aggregatable_reports));
-
-  if (!debug_aggregatable_reports.empty()) {
-    output.Set("debug_aggregatable_reports",
-               std::move(debug_aggregatable_reports));
-  }
-
-  if (!rejected_sources.empty())
-    output.Set("rejected_sources", std::move(rejected_sources));
-
-  if (!rejected_triggers.empty())
-    output.Set("rejected_triggers", std::move(rejected_triggers));
-
-  if (!replaced_event_level_reports.empty()) {
-    output.Set("replaced_event_level_reports",
-               std::move(replaced_event_level_reports));
-  }
-
-  return base::Value(std::move(output));
+  return base::Value(handler.TakeOutput());
 }
 
 }  // namespace content
diff --git a/content/test/data/first_party_sets/v4.sql b/content/test/data/first_party_sets/v4.sql
new file mode 100644
index 0000000..d7c7d03
--- /dev/null
+++ b/content/test/data/first_party_sets/v4.sql
@@ -0,0 +1,71 @@
+PRAGMA foreign_keys=OFF;
+
+BEGIN TRANSACTION;
+
+CREATE TABLE IF NOT EXISTS public_sets(
+  version TEXT NOT NULL,
+  site TEXT NOT NULL,
+  primary_site TEXT NOT NULL,
+  site_type INTEGER NOT NULL,
+  PRIMARY KEY(version, site)
+) WITHOUT ROWID;
+
+CREATE TABLE IF NOT EXISTS browser_context_sets_version (
+   browser_context_id TEXT PRIMARY KEY NOT NULL,
+   public_sets_version TEXT NOT NULL
+) WITHOUT ROWID;
+
+CREATE TABLE IF NOT EXISTS policy_configurations (
+   browser_context_id TEXT NOT NULL,
+   site TEXT NOT NULL,
+   primary_site TEXT, -- May be NULL if this row represents a deletion.
+   PRIMARY KEY (browser_context_id, site)
+) WITHOUT ROWID;
+
+CREATE TABLE IF NOT EXISTS manual_configurations (
+  browser_context_id TEXT NOT NULL,
+  site TEXT NOT NULL,
+  primary_site TEXT,
+  site_type INTEGER,
+  PRIMARY KEY(browser_context_id, site)
+) WITHOUT ROWID;
+
+CREATE TABLE IF NOT EXISTS browser_context_sites_to_clear (
+   browser_context_id TEXT NOT NULL,
+   site TEXT NOT NULL,
+   marked_at_run Integer NOT NULL,
+   PRIMARY KEY (browser_context_id, site)
+) WITHOUT ROWID;
+
+CREATE INDEX idx_marked_at_run_sites ON browser_context_sites_to_clear (marked_at_run);
+
+CREATE TABLE IF NOT EXISTS browser_contexts_cleared (
+   browser_context_id TEXT PRIMARY KEY NOT NULL,
+   cleared_at_run Integer NOT NULL
+) WITHOUT ROWID;
+
+CREATE INDEX idx_cleared_at_run_browser_contexts ON browser_contexts_cleared (cleared_at_run);
+
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
+
+INSERT INTO meta VALUES('version','4');
+INSERT INTO meta VALUES('last_compatible_version','2');
+INSERT INTO meta VALUES('run_count','1');
+
+INSERT INTO public_sets VALUES('0.0.1', 'https://aaa.test', 'https://bbb.test', 1),
+                              ('0.0.1', 'https://bbb.test', 'https://bbb.test', 0);
+INSERT INTO browser_context_sets_version VALUES('b0', '0.0.1'),
+                                               ('b1', '0.0.1'),
+                                               ('b2', '0.0.1');
+
+-- b0: has sites to clear and has performed the clearing.
+-- b1: has sites to clear but has not performed the clearing.
+-- b2: has policy modifications but has no site to clear.
+INSERT INTO browser_context_sites_to_clear VALUES('b0', 'https://example.test', 1),
+                                                 ('b1', 'https://example.test', 1);
+INSERT INTO browser_contexts_cleared VALUES('b0', 1);
+INSERT INTO policy_configurations VALUES('b2', 'https://member1.test','https://example.test'),
+                                       ('b2', 'https://member2.test',NULL);
+INSERT INTO manual_configurations VALUES('b0', 'https://ccc.test','https://ddd.test', 1),
+                              ('b0', 'https://ddd.test', 'https://ddd.test', 0);
+COMMIT;
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index ecb811d..c7f8943 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -631,7 +631,8 @@
 #####################
 
 crbug.com/1215700 [ chromeos no-passthrough ] deqp/functional/gles3/negativetextureapi.html [ Failure ]
-
+crbug.com/1380411 [ chromeos passthrough ] conformance2/textures/canvas_sub_rectangle/tex-3d-* [ Skip ]
+crbug.com/1380411 [ chromeos passthrough ] conformance2/textures/canvas_sub_rectangle/tex-2d-r8ui-red_integer-unsigned_byte.html [ Failure ]
 crbug.com/1210240 [ chromeos chromeos-board-amd64-generic no-passthrough ] conformance2/textures/canvas_sub_rectangle/tex-2d-r8ui-red_integer-unsigned_byte.html [ Failure ]
 crbug.com/1210240 [ chromeos chromeos-board-amd64-generic no-passthrough ] conformance2/textures/webgl_canvas/tex-2d-r8ui-red_integer-unsigned_byte.html [ Failure ]
 crbug.com/1213198 [ chromeos chromeos-board-amd64-generic ] WebglExtension_OVR_multiview2 [ Failure ]
diff --git a/content/web_test/renderer/web_frame_test_proxy.cc b/content/web_test/renderer/web_frame_test_proxy.cc
index 376a78b..30000db 100644
--- a/content/web_test/renderer/web_frame_test_proxy.cc
+++ b/content/web_test/renderer/web_frame_test_proxy.cc
@@ -559,9 +559,6 @@
     case ax::mojom::Event::kCheckedStateChanged:
       event_name = "CheckedStateChanged";
       break;
-    case ax::mojom::Event::kChildrenChanged:
-      event_name = "ChildrenChanged";
-      break;
     case ax::mojom::Event::kClicked:
       event_name = "Clicked";
       break;
@@ -631,6 +628,7 @@
     // RenderAccessibilityImpl::IsImmediateProcessingRequiredForEvent().
     case ax::mojom::Event::kAlert:
     case ax::mojom::Event::kAutocorrectionOccured:
+    case ax::mojom::Event::kChildrenChanged:
     case ax::mojom::Event::kControlsChanged:
     case ax::mojom::Event::kEndOfTest:
     case ax::mojom::Event::kFocusAfterMenuClose:
diff --git a/docs/clang_sheriffing.md b/docs/clang_sheriffing.md
index c15297d3..07b594c8 100644
--- a/docs/clang_sheriffing.md
+++ b/docs/clang_sheriffing.md
@@ -359,11 +359,11 @@
 
 In other cases, it may be interesting to take a closer look at the
 code generation for a single file. This can be done using LLD's
-support for distributed ThinLTO. The linker takes a `-thinlto-index-only`
+support for distributed ThinLTO. The linker takes a `--thinlto-index-only`
 option that does whole program analysis and writes index files:
 
 ```sh
-$ clang++ -fuse-ld=lld -Wl,-thinlto-index-only -o ./base_unittests @base_unittests.expanded.rsp
+$ clang++ -fuse-ld=lld -Wl,--thinlto-index-only -o ./base_unittests @base_unittests.expanded.rsp
 ```
 
 This creates `.thinlto.bc` files next to object files used by the link (e.g.
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index c8f8f4e..3eecf8d7 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -148,6 +148,8 @@
         updater is inactive, it may qualify and activate, or uninstall itself.
         If this version of the updater is active, it may check for updates for
         applications, unregister uninstalled applications, and more.
+*   --wakeall
+    *   Runs --wake for every updater version installed in this scope.
 *   --crash-me
     *   Record a backtrace in the log, crash the program, save a crash dump,
         and report the crash.
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index e604608..1793799 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -622,6 +622,15 @@
   }
 
   void Start() {
+    // Owner of BrowserContext should ensure that all WebContents are closed
+    // before starting BrowserContext destruction, but this doesn't stop
+    // incoming URLLoaderFactory IPCs which may still be in-flight until (as
+    // part of BrowserContext destruction sequence) OnBrowserContextDestroyed
+    // below is called (which will prevent future IPCs by calling
+    // DisconnectReceiversAndDestroy).  Note that DisconnectReceiversAndDestroy
+    // will only stop future ExtensionURLLoaderFactory IPCs, but it won't stop
+    // future ExtensionURLLoader IPCs - this is okay, because the loader doesn't
+    // directly interact with the BrowserContext.
     if (browser_context_->ShutdownStarted()) {
       CompleteRequestAndDeleteThis(net::ERR_FAILED);
       return;
@@ -930,6 +939,11 @@
 
     // Return an unbound |pending_remote| if the |browser_context| has already
     // started shutting down.
+    //
+    // TODO(https://crbug.com/1376879): This should be a DCHECK or a CHECK
+    // (no new ExtensionURLLoaderFactory should be created after BrowserContext
+    // shutdown has started *if* all WebContents got closed before starting the
+    // shutdown).
     if (browser_context->ShutdownStarted())
       return pending_remote;
 
diff --git a/fuchsia_web/shell/BUILD.gn b/fuchsia_web/shell/BUILD.gn
index fe635dc..17eb3aa 100644
--- a/fuchsia_web/shell/BUILD.gn
+++ b/fuchsia_web/shell/BUILD.gn
@@ -96,6 +96,12 @@
 if (enable_cast_receiver) {
   fuchsia_component("cast_streaming_shell_component") {
     testonly = true
+    manifest = "cast_streaming_shell.cml"
+    data_deps = [ ":cast_streaming_shell_exe" ]
+  }
+
+  fuchsia_component("cast_streaming_shell_component_v1") {
+    testonly = true
     manifest = "cast_streaming_shell.cmx"
     data_deps = [ ":cast_streaming_shell_exe" ]
   }
@@ -103,7 +109,10 @@
   fuchsia_package("cast_streaming_shell_pkg") {
     testonly = true
     package_name = "cast_streaming_shell"
-    deps = [ ":cast_streaming_shell_component" ]
+    deps = [
+      ":cast_streaming_shell_component",
+      ":cast_streaming_shell_component_v1",
+    ]
   }
 
   fuchsia_package_installer("cast_streaming_shell") {
diff --git a/fuchsia_web/shell/cast_streaming_shell.cml b/fuchsia_web/shell/cast_streaming_shell.cml
new file mode 100644
index 0000000..8765b550
--- /dev/null
+++ b/fuchsia_web/shell/cast_streaming_shell.cml
@@ -0,0 +1,74 @@
+// 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: [
+    "syslog/client.shard.cml",
+    "vulkan/client.shard.cml",
+
+    // CML shards intended for tests are used here because this component is
+    // launched as a test. While it doesn't fit the typical use-case for a test
+    // component, it's a useful way to be able to launch the component from a
+    // host tool and have it run somewhere it can get the capabilities it needs
+    // to function correctly.
+    "//build/config/fuchsia/test/chromium_test_facet.shard.test-cml",
+    "//build/config/fuchsia/test/elf_test_ambient_exec_runner.shard.test-cml",
+  ],
+  program: {
+    binary: "cast_streaming_shell_exe",
+  },
+  use: [
+    {
+      protocol: [
+        "fuchsia.feedback.ComponentDataRegister",
+        "fuchsia.feedback.CrashReportingProductRegister",
+        "fuchsia.sys.Environment",
+        "fuchsia.sys.Launcher",
+        "fuchsia.sys.Loader",
+      ],
+    },
+    {
+      storage: "data",
+      path: "/data",
+    },
+    {
+      storage: "tmp",
+      path: "/tmp",
+    },
+    {
+      protocol: [
+        "fuchsia.accessibility.semantics.SemanticsManager",
+        "fuchsia.buildinfo.Provider",
+        "fuchsia.device.NameProvider",
+        "fuchsia.fonts.Provider",
+        "fuchsia.intl.PropertyProvider",
+        "fuchsia.kernel.VmexResource",
+        "fuchsia.logger.LogSink",
+        "fuchsia.media.Audio",
+        "fuchsia.media.AudioDeviceEnumerator",
+        "fuchsia.media.ProfileProvider",
+        "fuchsia.media.SessionAudioConsumerFactory",
+        "fuchsia.mediacodec.CodecFactory",
+        "fuchsia.memorypressure.Provider",
+        "fuchsia.net.interfaces.State",
+        "fuchsia.net.name.Lookup",
+        "fuchsia.posix.socket.Provider",
+        "fuchsia.process.Launcher",
+        "fuchsia.sysmem.Allocator",
+        "fuchsia.ui.composition.Allocator",
+        "fuchsia.ui.composition.Flatland",
+        "fuchsia.ui.policy.Presenter",
+        "fuchsia.ui.scenic.Scenic",
+      ],
+    },
+    {
+      protocol: "fuchsia.tracing.perfetto.ProducerConnector",
+      availability: "optional",
+    },
+  ],
+  facets: {
+    "fuchsia.test": {
+      "deprecated-allowed-packages": ["web_engine"],
+    },
+  },
+}
diff --git a/gpu/ipc/service/dcomp_texture_win.cc b/gpu/ipc/service/dcomp_texture_win.cc
index f09ba6c..fd9b582 100644
--- a/gpu/ipc/service/dcomp_texture_win.cc
+++ b/gpu/ipc/service/dcomp_texture_win.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/notreached.h"
+#include "base/power_monitor/power_monitor.h"
 #include "base/win/windows_types.h"
 #include "components/viz/common/resources/resource_format.h"
 #include "components/viz/common/resources/resource_sizes.h"
@@ -25,6 +26,7 @@
 #include "ipc/ipc_mojo_bootstrap.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/video_types.h"
 #include "ui/gl/dcomp_surface_registry.h"
 #include "ui/gl/scoped_make_current.h"
 
@@ -32,8 +34,8 @@
 
 namespace {
 
-constexpr base::TimeDelta kParentWindowPosPollingPeriod =
-    base::Milliseconds(1000);
+constexpr base::TimeDelta kParentWindowPosPollingPeriod = base::Seconds(1);
+constexpr base::TimeDelta kPowerChangeDetectionGracePeriod = base::Seconds(2);
 
 class DCOMPTextureRepresentation : public OverlayImageRepresentation {
  public:
@@ -129,21 +131,26 @@
   IPC::ScopedAllowOffSequenceChannelAssociatedBindings allow_binding;
   receiver_.Bind(std::move(receiver), runner);
   context_state_->AddContextLostObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
   channel_->AddRoute(route_id, sequence_);
 }
 
 DCOMPTexture::~DCOMPTexture() {
+  DVLOG(1) << __func__;
   // |channel_| is always released before GpuChannel releases its reference to
   // this class.
   DCHECK(!channel_);
 
   context_state_->RemoveContextLostObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
+
   if (window_pos_timer_.IsRunning()) {
     window_pos_timer_.Stop();
   }
 }
 
 void DCOMPTexture::ReleaseChannel() {
+  DVLOG(1) << __func__;
   DCHECK(channel_);
 
   receiver_.ResetFromAnotherSequenceUnsafe();
@@ -151,10 +158,43 @@
   channel_->scheduler()->DestroySequence(sequence_);
   sequence_ = SequenceId();
   channel_ = nullptr;
+
+  ResetSizeIfNeeded();
 }
 
 void DCOMPTexture::OnContextLost() {
-  context_lost_ = true;
+  DVLOG(1) << __func__;
+}
+
+// TODO(xhwang): Also observe GPU LUID change.
+void DCOMPTexture::OnResume() {
+  DVLOG(1) << __func__;
+  last_power_change_time_ = base::TimeTicks::Now();
+  ResetSizeIfNeeded();
+}
+
+void DCOMPTexture::ResetSizeIfNeeded() {
+  DVLOG(2) << __func__;
+  // For `kHardwareProtected` video frame, when hardware content reset happens,
+  // e.g. OS suspend/resume or GPU hot swap, existing video frames become stale
+  // and presenting them could cause issues like black screen flash (see
+  // crbug.com/1384544). So we set `size_` to (1, 1) so that DComp surface
+  // resources will be released (see SwapChainPresenter::PresentDCOMPSurface()).
+  // We don't know for sure whether hardware content reset happened. So we check
+  // whether power suspend/resume or GPU change happened recently as a hint.
+  // Since it's a hint, to prevent breaking normal playback, we only do this
+  // when the video frame is orphaned (the media Renderer has been suspended or
+  // destroyed, but we are still showing the last frame), which will trigger
+  // `ReleaseChannel()` and set `channel_` to null.
+  if (!channel_ &&
+      protected_video_type_ == gfx::ProtectedVideoType::kHardwareProtected &&
+      base::TimeTicks::Now() - last_power_change_time_ <
+          kPowerChangeDetectionGracePeriod) {
+    DVLOG(1) << __func__
+             << ": Resetting size to {1,1} to release dcomp surface resources "
+                "and prevent stale content from being displayed";
+    size_ = gfx::Size(1, 1);
+  }
 }
 
 void DCOMPTexture::StartListening(
@@ -258,6 +298,16 @@
     SendOutputRect();
 }
 
+void DCOMPTexture::SetProtectedVideoType(
+    gfx::ProtectedVideoType protected_video_type) {
+  if (protected_video_type == protected_video_type_)
+    return;
+
+  DVLOG(2) << __func__ << ": protected_video_type="
+           << static_cast<int>(protected_video_type);
+  protected_video_type_ = protected_video_type;
+}
+
 void DCOMPTexture::SendOutputRect() {
   if (!client_)
     return;
diff --git a/gpu/ipc/service/dcomp_texture_win.h b/gpu/ipc/service/dcomp_texture_win.h
index dac0a09..a5125d6 100644
--- a/gpu/ipc/service/dcomp_texture_win.h
+++ b/gpu/ipc/service/dcomp_texture_win.h
@@ -10,6 +10,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/power_monitor/power_observer.h"
 #include "base/timer/timer.h"
 #include "base/unguessable_token.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
@@ -29,6 +30,7 @@
 
 class DCOMPTexture : public gl::DCOMPSurfaceProxy,
                      public SharedContextState::ContextLostObserver,
+                     public base::PowerSuspendObserver,
                      public mojom::DCOMPTexture {
  public:
   // A nullptr is returned if it fails to create one.
@@ -46,6 +48,8 @@
   HANDLE GetSurfaceHandle() override;
   void SetParentWindow(HWND parent) override;
   void SetRect(const gfx::Rect& window_relative_rect) override;
+  void SetProtectedVideoType(
+      gfx::ProtectedVideoType protected_video_type) override;
 
  private:
   DCOMPTexture(GpuChannel* channel,
@@ -57,6 +61,9 @@
   // SharedContextState::ContextLostObserver implementation.
   void OnContextLost() override;
 
+  // base::PowerSuspendObserver implementation.
+  void OnResume() override;
+
   // mojom::DCOMPTexture implementation.
   void StartListening(
       mojo::PendingAssociatedRemote<mojom::DCOMPTextureClient> client) override;
@@ -69,28 +76,37 @@
 
   void OnUpdateParentWindowRect();
   void SendOutputRect();
+  void ResetSizeIfNeeded();
 
   // Size of {1, 1} to signify the Media Foundation rendering pipeline is not
-  // ready to setup DCOMP video yet.
+  // ready to setup DCOMP video yet, or should not display due to hardware
+  // context reset.
   gfx::Size size_ = gfx::Size(1, 1);
+
   base::win::ScopedHandle surface_handle_;
   HWND last_parent_ = nullptr;
+  gfx::ProtectedVideoType protected_video_type_ =
+      gfx::ProtectedVideoType::kClear;
 
-  bool context_lost_ = false;
   bool shared_image_mailbox_created_ = false;
   raw_ptr<GpuChannel> channel_ = nullptr;
   const int32_t route_id_;
   scoped_refptr<SharedContextState> context_state_;
   SequenceId sequence_;
 
-  mojo::AssociatedReceiver<mojom::DCOMPTexture> receiver_;
-  mojo::AssociatedRemote<mojom::DCOMPTextureClient> client_;
-
   gfx::Rect last_output_rect_;
   gfx::Rect parent_window_rect_;
   gfx::Rect window_relative_rect_;
   base::RepeatingTimer window_pos_timer_;
 
+  // Last time when a power resume or GPU change happened. This is used to
+  // decide whether there is a risk that hardware context reset happened and we
+  // should release dcomp surface.
+  base::TimeTicks last_power_change_time_;
+
+  mojo::AssociatedReceiver<mojom::DCOMPTexture> receiver_;
+  mojo::AssociatedRemote<mojom::DCOMPTextureClient> client_;
+
   base::WeakPtrFactory<DCOMPTexture> weak_factory_{this};
 };
 
diff --git a/headless/app/headless_shell_command_line.cc b/headless/app/headless_shell_command_line.cc
index a7d0b24..d15de03 100644
--- a/headless/app/headless_shell_command_line.cc
+++ b/headless/app/headless_shell_command_line.cc
@@ -215,13 +215,6 @@
       return false;
   }
 
-  if (command_line.HasSwitch(switches::kHideScrollbars)) {
-    builder.SetOverrideWebPreferencesCallback(
-        base::BindRepeating([](blink::web_pref::WebPreferences* preferences) {
-          preferences->hide_scrollbars = true;
-        }));
-  }
-
   if (command_line.HasSwitch(switches::kUserAgent)) {
     std::string user_agent =
         command_line.GetSwitchValueASCII(switches::kUserAgent);
diff --git a/headless/app/headless_shell_switches.cc b/headless/app/headless_shell_switches.cc
index f0d31a6..e2ddf46 100644
--- a/headless/app/headless_shell_switches.cc
+++ b/headless/app/headless_shell_switches.cc
@@ -41,9 +41,6 @@
 // Instructs headless_shell to print document.body.innerHTML to stdout.
 const char kDumpDom[] = "dump-dom";
 
-// Hide scrollbars from screenshots.
-const char kHideScrollbars[] = "hide-scrollbars";
-
 // Specifies which encryption storage backend to use. Possible values are
 // kwallet, kwallet5, gnome, gnome-keyring, gnome-libsecret, basic. Any other
 // value will lead to Chrome detecting the best backend automatically.
diff --git a/headless/app/headless_shell_switches.h b/headless/app/headless_shell_switches.h
index 3f2456b3..0d76074d 100644
--- a/headless/app/headless_shell_switches.h
+++ b/headless/app/headless_shell_switches.h
@@ -20,7 +20,6 @@
 HEADLESS_EXPORT extern const char kDumpDom[];
 HEADLESS_EXPORT extern const char kEnableBeginFrameControl[];
 HEADLESS_EXPORT extern const char kEnableCrashReporter[];
-HEADLESS_EXPORT extern const char kHideScrollbars[];
 HEADLESS_EXPORT extern const char kPasswordStore[];
 HEADLESS_EXPORT extern const char kPrintToPDF[];
 HEADLESS_EXPORT extern const char kPrintToPDFNoHeader[];
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 3161448f..36f5a28 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -54688,6 +54688,7 @@
       name: "android-launcher"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
+      dimensions: "cores:8"
       dimensions: "os:Ubuntu-18.04"
       dimensions: "pool:luci.chromium.ci"
       dimensions: "ssd:0"
@@ -54854,6 +54855,100 @@
       }
     }
     builders {
+      name: "linux-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": "Linux Tests",'
+        '        "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: "mac-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": "Mac12 Tests",'
+        '        "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: "runner"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -54910,6 +55005,53 @@
         }
       }
     }
+    builders {
+      name: "win-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": "Win10 Tests x64",'
+        '        "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
+      }
+    }
   }
 }
 buckets {
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 43d6e4d0..a9d0d63 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -17263,8 +17263,17 @@
     name: "buildbucket/luci.chromium.reviver/lacros-coordinator"
   }
   builders {
+    name: "buildbucket/luci.chromium.reviver/linux-launcher"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.reviver/mac-launcher"
+  }
+  builders {
     name: "buildbucket/luci.chromium.reviver/runner"
   }
+  builders {
+    name: "buildbucket/luci.chromium.reviver/win-launcher"
+  }
   builder_view_only: true
 }
 consoles {
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index c9d31cf..4ce6262 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -4936,6 +4936,16 @@
   }
 }
 job {
+  id: "linux-launcher"
+  realm: "reviver"
+  schedule: "0 5-11/3 * * *"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "reviver"
+    builder: "linux-launcher"
+  }
+}
+job {
   id: "linux-official"
   realm: "ci"
   buildbucket {
@@ -5260,6 +5270,16 @@
   }
 }
 job {
+  id: "mac-launcher"
+  realm: "reviver"
+  schedule: "0 5-11/3 * * *"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "reviver"
+    builder: "mac-launcher"
+  }
+}
+job {
   id: "mac-official"
   realm: "ci"
   buildbucket {
@@ -5561,6 +5581,16 @@
   }
 }
 job {
+  id: "win-launcher"
+  realm: "reviver"
+  schedule: "0 5-11/3 * * *"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "reviver"
+    builder: "win-launcher"
+  }
+}
+job {
   id: "win-official"
   realm: "ci"
   buildbucket {
diff --git a/infra/config/subprojects/reviver/reviver.star b/infra/config/subprojects/reviver/reviver.star
index 33a4d1e..deb6bfa9 100644
--- a/infra/config/subprojects/reviver/reviver.star
+++ b/infra/config/subprojects/reviver/reviver.star
@@ -38,6 +38,8 @@
     bucket = "reviver",
     list_view = "reviver",
     service_account = "reviver-builder@chops-service-accounts.iam.gserviceaccount.com",
+    os = os.LINUX_DEFAULT,
+    pool = ci.DEFAULT_POOL,
 
     # TODO(crbug.com/1362440): remove this.
     omit_python2 = False,
@@ -53,6 +55,7 @@
     ],
     os = os.LINUX_DEFAULT,
     pool = ci.DEFAULT_POOL,
+    cores = 8,
     # 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 * * *",
 )
@@ -69,6 +72,36 @@
     schedule = "0 5,8,11 * * *",
 )
 
+polymorphic.launcher(
+    name = "linux-launcher",
+    runner = "reviver/runner",
+    target_builders = [
+        "ci/Linux Tests",
+    ],
+    # To avoid peak hours, we run it at 5~11 UTC, 21~27 PST.
+    schedule = "0 5-11/3 * * *",
+)
+
+polymorphic.launcher(
+    name = "win-launcher",
+    runner = "reviver/runner",
+    target_builders = [
+        "ci/Win10 Tests x64",
+    ],
+    # To avoid peak hours, we run it at 5~11 UTC, 21~27 PST.
+    schedule = "0 5-11/3 * * *",
+)
+
+polymorphic.launcher(
+    name = "mac-launcher",
+    runner = "reviver/runner",
+    target_builders = [
+        "ci/Mac12 Tests",
+    ],
+    # To avoid peak hours, we run it at 5~11 UTC, 21~27 PST.
+    schedule = "0 5-11/3 * * *",
+)
+
 # A coordinator of slightly aggressive scheduling with effectively unlimited
 # test bot capacity for fuchsia.
 polymorphic.launcher(
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index f5b13aa9..1de3f20 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -602,17 +602,31 @@
     deps += [ "//ios/chrome/app/startup:sandbox_dump" ]
   }
 
+  assert_no_deps = []
+
   if (ios_chrome_links_with_material_components_framework) {
     deps += [
       "//ios/third_party/material_components_ios:material_components_ios+bundle",
       "//ios/third_party/material_components_ios:material_components_ios+link",
     ]
   } else {
-    assert_no_deps = [
+    assert_no_deps += [
       "//ios/third_party/material_components_ios:material_components_ios+bundle",
       "//ios/third_party/material_components_ios:material_components_ios+link",
     ]
   }
+
+  if (ios_chrome_links_with_lottie_framework) {
+    deps += [
+      "//ios/third_party/lottie:lottie+bundle",
+      "//ios/third_party/lottie:lottie+link",
+    ]
+  } else {
+    assert_no_deps += [
+      "//ios/third_party/lottie:lottie+bundle",
+      "//ios/third_party/lottie:lottie+link",
+    ]
+  }
 }
 
 source_set("multitasking_test_app_delegate") {
diff --git a/ios/chrome/browser/commerce/price_notifications/BUILD.gn b/ios/chrome/browser/commerce/price_notifications/BUILD.gn
new file mode 100644
index 0000000..b1a7b51
--- /dev/null
+++ b/ios/chrome/browser/commerce/price_notifications/BUILD.gn
@@ -0,0 +1,18 @@
+# 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.
+
+source_set("price_notifications") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "price_notifications_tab_helper.h",
+    "price_notifications_tab_helper.mm",
+  ]
+  deps = [
+    "//base",
+    "//components/commerce/core:shopping_service",
+    "//ios/chrome/browser/commerce:shopping_service",
+    "//ios/web/public",
+    "//ios/web/public:web_state_observer",
+  ]
+}
diff --git a/ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.h b/ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.h
new file mode 100644
index 0000000..224fae0
--- /dev/null
+++ b/ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.h
@@ -0,0 +1,50 @@
+// 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 IOS_CHROME_BROWSER_COMMERCE_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_COMMERCE_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_TAB_HELPER_H_
+
+#import "base/scoped_observation.h"
+#import "ios/web/public/web_state.h"
+#import "ios/web/public/web_state_observer.h"
+#import "ios/web/public/web_state_user_data.h"
+
+namespace commerce {
+class ShoppingService;
+}  // namespace commerce
+
+// The PriceNotificationTabHelper's purpose is to initiate display of the Price
+// Tracking IPH when the user navigates to a webpage that contains an item that
+// can be price tracked.
+class PriceNotificationsTabHelper
+    : public web::WebStateObserver,
+      public web::WebStateUserData<PriceNotificationsTabHelper> {
+ public:
+  PriceNotificationsTabHelper(const PriceNotificationsTabHelper&) = delete;
+  PriceNotificationsTabHelper& operator=(const PriceNotificationsTabHelper&) =
+      delete;
+
+  ~PriceNotificationsTabHelper() override;
+
+ private:
+  friend class web::WebStateUserData<PriceNotificationsTabHelper>;
+
+  explicit PriceNotificationsTabHelper(web::WebState* web_state);
+
+  // WebStateObserver::
+  void WebStateDestroyed(web::WebState* web_state) override;
+  void DidFinishNavigation(web::WebState* web_state,
+                           web::NavigationContext* navigation_context) override;
+
+  // Manages the tab helper's observation of the WebState
+  base::ScopedObservation<web::WebState, web::WebStateObserver>
+      web_state_observation_{this};
+
+  // The service responsible for determining whether a given webpage can be
+  // price tracked.
+  commerce::ShoppingService* shopping_service_ = nullptr;
+
+  WEB_STATE_USER_DATA_KEY_DECL();
+};
+#endif  // IOS_CHROME_BROWSER_COMMERCE_PRICE_NOTIFICATIONS_PRICE_NOTIFICATIONS_TAB_HELPER_H_
diff --git a/ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.mm b/ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.mm
new file mode 100644
index 0000000..b63fc940
--- /dev/null
+++ b/ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.mm
@@ -0,0 +1,48 @@
+// 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 "ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.h"
+
+#import "components/commerce/core/shopping_service.h"
+#import "ios/chrome/browser/commerce/shopping_service_factory.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+void OnProductInfoUrl(
+    const GURL& productURL,
+    const absl::optional<commerce::ProductInfo>& product_info) {
+  if (!product_info)
+    return;
+
+  // TODO(crbug.com/1362350) Once the PriceNotificationsTabHelper
+  // has landed, this section will display the IPH.
+}
+
+}  // namespace
+
+PriceNotificationsTabHelper::PriceNotificationsTabHelper(
+    web::WebState* web_state) {
+  web_state_observation_.Observe(web_state);
+  shopping_service_ = commerce::ShoppingServiceFactory::GetForBrowserState(
+      web_state->GetBrowserState());
+}
+
+PriceNotificationsTabHelper::~PriceNotificationsTabHelper() = default;
+
+void PriceNotificationsTabHelper::DidFinishNavigation(
+    web::WebState* web_state,
+    web::NavigationContext* navigation_context) {
+  shopping_service_->GetProductInfoForUrl(web_state->GetVisibleURL(),
+                                          base::BindOnce(&OnProductInfoUrl));
+}
+
+void PriceNotificationsTabHelper::WebStateDestroyed(web::WebState* web_state) {
+  web_state_observation_.Reset();
+}
+
+WEB_STATE_USER_DATA_KEY_IMPL(PriceNotificationsTabHelper)
diff --git a/ios/chrome/browser/reading_list/reading_list_download_service.h b/ios/chrome/browser/reading_list/reading_list_download_service.h
index 26acf27a..d0bf92a 100644
--- a/ios/chrome/browser/reading_list/reading_list_download_service.h
+++ b/ios/chrome/browser/reading_list/reading_list_download_service.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/scoped_observation.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/reading_list/core/reading_list_model_observer.h"
 #include "ios/chrome/browser/reading_list/url_downloader.h"
@@ -114,6 +115,13 @@
       distiller_page_factory_;
   std::unique_ptr<dom_distiller::DistillerFactory> distiller_factory_;
 
+  base::ScopedObservation<ReadingListModel, ReadingListModelObserver>
+      model_observation_{this};
+  base::ScopedObservation<
+      network::NetworkConnectionTracker,
+      network::NetworkConnectionTracker::NetworkConnectionObserver>
+      network_observation_{this};
+
   base::WeakPtrFactory<ReadingListDownloadService> weak_ptr_factory_;
 };
 
diff --git a/ios/chrome/browser/reading_list/reading_list_download_service.mm b/ios/chrome/browser/reading_list/reading_list_download_service.mm
index 5bc9f15..100249b 100644
--- a/ios/chrome/browser/reading_list/reading_list_download_service.mm
+++ b/ios/chrome/browser/reading_list/reading_list_download_service.mm
@@ -88,20 +88,14 @@
                           base::Unretained(this)),
       base::BindRepeating(&ReadingListDownloadService::OnDeleteEnd,
                           base::Unretained(this)));
-
-  GetApplicationContext()
-      ->GetNetworkConnectionTracker()
-      ->AddNetworkConnectionObserver(this);
+  network_observation_.Observe(
+      GetApplicationContext()->GetNetworkConnectionTracker());
 }
 
-ReadingListDownloadService::~ReadingListDownloadService() {
-  GetApplicationContext()
-      ->GetNetworkConnectionTracker()
-      ->RemoveNetworkConnectionObserver(this);
-}
+ReadingListDownloadService::~ReadingListDownloadService() = default;
 
 void ReadingListDownloadService::Initialize() {
-  reading_list_model_->AddObserver(this);
+  model_observation_.Observe(reading_list_model_);
 }
 
 base::FilePath ReadingListDownloadService::OfflineRoot() const {
@@ -109,7 +103,8 @@
 }
 
 void ReadingListDownloadService::Shutdown() {
-  reading_list_model_->RemoveObserver(this);
+  model_observation_.Reset();
+  network_observation_.Reset();
 }
 
 void ReadingListDownloadService::ReadingListModelLoaded(
diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.mm b/ios/chrome/browser/reading_list/reading_list_model_factory.mm
index 2836a97..3975be8 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_factory.mm
+++ b/ios/chrome/browser/reading_list/reading_list_model_factory.mm
@@ -14,7 +14,7 @@
 #import "components/pref_registry/pref_registry_syncable.h"
 #import "components/reading_list/core/reading_list_model_impl.h"
 #import "components/reading_list/core/reading_list_pref_names.h"
-#import "components/reading_list/core/reading_list_store.h"
+#import "components/reading_list/core/reading_list_sync_bridge.h"
 #import "components/sync/base/report_unrecoverable_error.h"
 #import "components/sync/model/client_tag_based_model_type_processor.h"
 #import "components/sync/model/model_type_store_service.h"
@@ -71,8 +71,8 @@
           syncer::READING_LIST,
           base::BindRepeating(&syncer::ReportUnrecoverableError,
                               ::GetChannel()));
-  auto store = std::make_unique<ReadingListStore>(std::move(store_factory),
-                                                  std::move(change_processor));
+  auto store = std::make_unique<ReadingListSyncBridge>(
+      std::move(store_factory), std::move(change_processor));
   std::unique_ptr<KeyedService> reading_list_model =
       std::make_unique<ReadingListModelImpl>(std::move(store),
                                              chrome_browser_state->GetPrefs(),
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm
index fda6169..255d9ac9 100644
--- a/ios/chrome/browser/signin/authentication_service.mm
+++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -239,9 +239,12 @@
                               loginMethodAndSyncState,
                               LOGIN_METHOD_AND_SYNC_STATE_COUNT);
   }
-  UMA_HISTOGRAM_COUNTS_100(
-      "Signin.IOSNumberOfDeviceAccounts",
-      [account_manager_service_->GetAllIdentities() count]);
+  if (GetServiceStatus() !=
+      AuthenticationService::ServiceStatus::SigninDisabledByInternal) {
+    UMA_HISTOGRAM_COUNTS_100(
+        "Signin.IOSNumberOfDeviceAccounts",
+        [account_manager_service_->GetAllIdentities() count]);
+  }
 
   // Clear signin errors on the accounts that had a specific MDM device status.
   // This will trigger services to fetch data for these accounts again.
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index 7242a4ce..d4c4357 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -61,6 +61,8 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/commerce",
     "//ios/chrome/browser/commerce:shopping_service",
+    "//ios/chrome/browser/commerce/price_notifications",
+    "//ios/chrome/browser/commerce/push_notification",
     "//ios/chrome/browser/complex_tasks",
     "//ios/chrome/browser/crash_report/breadcrumbs",
     "//ios/chrome/browser/download",
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index 482445f..ccfa0d4 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -28,6 +28,8 @@
 #import "ios/chrome/browser/autofill/form_suggestion_tab_helper.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/commerce/price_alert_util.h"
+#import "ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.h"
+#import "ios/chrome/browser/commerce/push_notification/push_notification_feature.h"
 #import "ios/chrome/browser/commerce/shopping_persisted_data_tab_helper.h"
 #import "ios/chrome/browser/commerce/shopping_service_factory.h"
 #import "ios/chrome/browser/complex_tasks/ios_task_tab_helper.h"
@@ -276,4 +278,8 @@
   }
 
   CaptivePortalTabHelper::CreateForWebState(web_state);
+
+  if (IsPriceNotificationsEnabled()) {
+    PriceNotificationsTabHelper::CreateForWebState(web_state);
+  }
 }
diff --git a/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.h b/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.h
index 478594e..4ce9dc7 100644
--- a/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.h
+++ b/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.h
@@ -35,11 +35,6 @@
 // Returns YES if some account restrictions are set.
 bool IsRestrictAccountsToPatternsEnabled();
 
-// Returns true if force signIn is set.
-// DEPRECATED. Needs to use AuthenticationService::GetServiceStatus().
-// TODO(crbug.com/1242320): Need to remove this method.
-bool IsForceSignInEnabled();
-
 // Returns true if the `dataType` is managed by policies (i.e. is not syncable).
 bool IsManagedSyncDataType(PrefService* pref_service,
                            SyncSetupService::SyncableDatatype dataType);
diff --git a/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.mm b/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.mm
index 6ebd7c9d..c1d7028 100644
--- a/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.mm
+++ b/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.mm
@@ -43,15 +43,6 @@
               .empty();
 }
 
-// TODO(crbug.com/1244632): Use the Authentication Service sign-in status API
-// instead of this when available.
-bool IsForceSignInEnabled() {
-  BrowserSigninMode policy_mode = static_cast<BrowserSigninMode>(
-      GetApplicationContext()->GetLocalState()->GetInteger(
-          prefs::kBrowserSigninPolicy));
-  return policy_mode == BrowserSigninMode::kForced;
-}
-
 bool IsManagedSyncDataType(PrefService* pref_service,
                            SyncSetupService::SyncableDatatype data_type) {
   return pref_service->FindPreference(kSyncableItemTypes.at(data_type))
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index e86a761..e2538ac 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -74,6 +74,7 @@
 #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
 #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.h"
 #import "ios/chrome/browser/ui/lens/lens_coordinator.h"
+#import "ios/chrome/browser/ui/main/layout_guide_util.h"
 #import "ios/chrome/browser/ui/main/scene_state.h"
 #import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
 #import "ios/chrome/browser/ui/main_content/main_content_ui.h"
@@ -975,6 +976,7 @@
         [[BackgroundTabAnimationView alloc]
             initWithFrame:CGRectMake(0, 0, kAnimatedViewSize, kAnimatedViewSize)
                 incognito:_isOffTheRecord];
+    animatedView.layoutGuideCenter = LayoutGuideCenterForBrowser(self.browser);
     __weak UIView* weakAnimatedView = animatedView;
     auto completionBlock = ^() {
       self.inNewTabAnimation = NO;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
index c5f7c1d..ad61a44 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
@@ -178,15 +178,18 @@
 
   [voice_search_button setAdjustsImageWhenHighlighted:NO];
 
-  UIImage* mic_image =
-      UseSymbols() ? DefaultSymbolWithPointSize(
-                         kMicrophoneSymbol, kSymbolContentSuggestionsPointSize)
-                   : [UIImage imageNamed:@"location_bar_voice"];
-  mic_image =
-      [mic_image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  UIImage* mic_image;
+  if (UseSymbols()) {
+    mic_image = DefaultSymbolWithPointSize(kMicrophoneSymbol,
+                                           kSymbolContentSuggestionsPointSize);
+    voice_search_button.tintColor = [UIColor colorNamed:kGrey600Color];
+  } else {
+    mic_image = [[UIImage imageNamed:@"location_bar_voice"]
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+    voice_search_button.tintColor = [UIColor colorNamed:kGrey500Color];
+  }
 
   [voice_search_button setImage:mic_image forState:UIControlStateNormal];
-  voice_search_button.tintColor = [UIColor colorNamed:kGrey500Color];
   [voice_search_button setAccessibilityLabel:l10n_util::GetNSString(
                                                  IDS_IOS_ACCNAME_VOICE_SEARCH)];
   [voice_search_button setAccessibilityIdentifier:@"Voice Search"];
diff --git a/ios/chrome/browser/ui/elements/instruction_view.mm b/ios/chrome/browser/ui/elements/instruction_view.mm
index 8add710e..d21390b 100644
--- a/ios/chrome/browser/ui/elements/instruction_view.mm
+++ b/ios/chrome/browser/ui/elements/instruction_view.mm
@@ -26,6 +26,8 @@
 constexpr CGFloat kSeparatorLeadingMargin = 60;
 constexpr CGFloat kSeparatorHeight = 0.5;
 constexpr CGFloat kIconLabelWidth = 30;
+// Height minimum for a line.
+constexpr CGFloat kMinimumLineHeight = 44;
 
 // Creates a view with `icon` in it.
 UIView* CreateIconView(UIImage* icon) {
@@ -202,6 +204,8 @@
                                                     constant:-kVerticalMargin];
   minimumLabelBottomMargin.priority = UILayoutPriorityDefaultHigh;
   [NSLayoutConstraint activateConstraints:@[
+    [line.heightAnchor
+        constraintGreaterThanOrEqualToConstant:kMinimumLineHeight],
     [bulletPointView.leadingAnchor constraintEqualToAnchor:line.leadingAnchor
                                                   constant:kLeadingMargin],
     [bulletPointView.centerYAnchor constraintEqualToAnchor:line.centerYAnchor],
diff --git a/ios/chrome/browser/ui/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
index 80e4805..009623de 100644
--- a/ios/chrome/browser/ui/recent_tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
@@ -64,6 +64,7 @@
     "recent_tabs_table_view_controller.h",
     "recent_tabs_table_view_controller.mm",
     "recent_tabs_table_view_controller_delegate.h",
+    "recent_tabs_table_view_controller_ui_delegate.h",
     "recent_tabs_transitioning_delegate.h",
     "recent_tabs_transitioning_delegate.mm",
     "sessions_sync_user_state.h",
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
index a25f5399..1490d40 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
@@ -18,8 +18,9 @@
 
 @protocol ApplicationCommands;
 @protocol RecentTabsMenuProvider;
-@protocol RecentTabsTableViewControllerDelegate;
 @protocol RecentTabsPresentationDelegate;
+@protocol RecentTabsTableViewControllerDelegate;
+@protocol RecentTabsTableViewControllerUIDelegate;
 @protocol TableViewFaviconDataSource;
 
 @interface RecentTabsTableViewController
@@ -36,6 +37,9 @@
 @property(nonatomic, assign) WindowOpenDisposition restoredTabDisposition;
 // RecentTabsTableViewControllerDelegate delegate.
 @property(nonatomic, weak) id<RecentTabsTableViewControllerDelegate> delegate;
+// Delegate for UI-related events.
+@property(nonatomic, weak) id<RecentTabsTableViewControllerUIDelegate>
+    UIDelegate;
 // Whether the updates of the RecentTabs should be ignored. Setting this to NO
 // would trigger a reload of the TableView.
 @property(nonatomic, assign) BOOL preventUpdates;
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
index 491e81a..e9e028e 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -53,6 +53,7 @@
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_provider.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_delegate.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_ui_delegate.h"
 #import "ios/chrome/browser/ui/recent_tabs/synced_sessions.h"
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_presenter.h"
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
@@ -1139,6 +1140,10 @@
              : kSeparationSpaceBetweenSections;
 }
 
+- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
+  [self.UIDelegate recentTabsScrollViewDidScroll:self];
+}
+
 #pragma mark - UITableViewDataSource
 
 - (UITableViewCell*)tableView:(UITableView*)tableView
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_ui_delegate.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_ui_delegate.h
new file mode 100644
index 0000000..17eac130
--- /dev/null
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_ui_delegate.h
@@ -0,0 +1,19 @@
+// 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 IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_UI_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_UI_DELEGATE_H_
+
+@class RecentTabsTableViewController;
+
+// Delegate for the RecentTabsTableViewController for all UI-related events.
+@protocol RecentTabsTableViewControllerUIDelegate
+
+// Tells the delegate that the scroll view scrolled.
+- (void)recentTabsScrollViewDidScroll:
+    (RecentTabsTableViewController*)recentTabsTableViewController;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_UI_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
index f00308d4..7d90d99 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
@@ -181,7 +181,7 @@
 TEST_F(ClearBrowsingDataManagerTest, TestModel) {
   [manager_ loadModel:model_];
 
-  EXPECT_EQ(3, [model_ numberOfSections]);
+  EXPECT_EQ(2, [model_ numberOfSections]);
   EXPECT_EQ(
       1,
       [model_ numberOfItemsInSection:[model_ sectionForSectionIdentifier:
@@ -190,11 +190,6 @@
       5,
       [model_ numberOfItemsInSection:[model_ sectionForSectionIdentifier:
                                                  SectionIdentifierDataTypes]]);
-  EXPECT_EQ(
-      0,
-      [model_
-          numberOfItemsInSection:[model_ sectionForSectionIdentifier:
-                                             SectionIdentifierSavedSiteData]]);
 }
 
 // Tests model is set up with correct number of items and sections if signed in
diff --git a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_egtest.mm b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_egtest.mm
index c0f71678..7c2dcea 100644
--- a/ios/chrome/browser/ui/settings/price_notifications/price_notifications_egtest.mm
+++ b/ios/chrome/browser/ui/settings/price_notifications/price_notifications_egtest.mm
@@ -32,9 +32,12 @@
   // parameters.
   std::string params =
       ":enable_price_tracking/true/enable_price_notification/true";
+  std::string priceNotificationsFlag =
+      std::string(commerce::kCommercePriceTracking.name) + params;
+  std::string shoppingListFlag = std::string("ShoppingList");
+
   config.additional_args.push_back(
-      "--enable-features=" +
-      std::string(commerce::kCommercePriceTracking.name) + params);
+      "--enable-features=" + priceNotificationsFlag + "," + shoppingListFlag);
   return config;
 }
 
diff --git a/ios/chrome/browser/ui/settings/price_notifications/tracking_price/tracking_price_egtest.mm b/ios/chrome/browser/ui/settings/price_notifications/tracking_price/tracking_price_egtest.mm
index 80e0cca..2993b13 100644
--- a/ios/chrome/browser/ui/settings/price_notifications/tracking_price/tracking_price_egtest.mm
+++ b/ios/chrome/browser/ui/settings/price_notifications/tracking_price/tracking_price_egtest.mm
@@ -32,9 +32,12 @@
   // parameters.
   std::string params =
       ":enable_price_tracking/true/enable_price_notification/true";
+  std::string priceNotificationsFlag =
+      std::string(commerce::kCommercePriceTracking.name) + params;
+  std::string shoppingListFlag = std::string("ShoppingList");
+
   config.additional_args.push_back(
-      "--enable-features=" +
-      std::string(commerce::kCommercePriceTracking.name) + params);
+      "--enable-features=" + priceNotificationsFlag + "," + shoppingListFlag);
 
   return config;
 }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
index f5f50c1..9b3b82e2 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
@@ -115,6 +115,8 @@
     "tab_grid_new_tab_button.mm",
     "tab_grid_page_control.h",
     "tab_grid_page_control.mm",
+    "tab_grid_toolbars_utils.h",
+    "tab_grid_toolbars_utils.mm",
     "tab_grid_top_toolbar.h",
     "tab_grid_top_toolbar.mm",
     "tab_grid_view_controller.h",
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h
index cf2b5294..b403b54 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h
@@ -86,6 +86,9 @@
 // Tells the delegate that the grid view controller cells did end dragging.
 - (void)gridViewControllerDragSessionDidEnd:
     (GridViewController*)gridViewController;
+// Tells the delegate that the grid view controller did scroll.
+- (void)gridViewControllerScrollViewDidScroll:
+    (GridViewController*)gridViewController;
 
 @end
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
index 4f40381..4b12e4f 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
@@ -905,6 +905,7 @@
 }
 
 - (void)scrollViewDidScroll:(UIScrollView*)scrollView {
+  [self.delegate gridViewControllerScrollViewDidScroll:self];
   if (!self.thumbStripEnabled)
     return;
   [self updateFractionVisibleOfLastItem];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller_unittest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller_unittest.mm
index c36cf69..74d13e1 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller_unittest.mm
@@ -79,6 +79,11 @@
   // No-op for unittests.
 }
 
+- (void)gridViewControllerScrollViewDidScroll:
+    (GridViewController*)gridViewController {
+  // No-op for unittests.
+}
+
 @end
 
 class GridViewControllerTest : public RootViewControllerTest {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.h
index 05eb6eb..c277c34 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.h
@@ -26,6 +26,7 @@
 //   Remote page:    [                                                  ]
 //   Selection mode: [CloseTabButton       shareButton       AddToButton]
 @interface TabGridBottomToolbar : UIView
+
 // This property together with `mode` and self.traitCollection control the items
 // shown in toolbar and its background color. Setting this property will also
 // set it on `newTabButton`.
@@ -78,6 +79,10 @@
 - (void)hide;
 // Recovers the normal appearance for tab grid transition animation.
 - (void)show;
+// Updates the appearance of the this toolbar, based on whether the content
+// below it is `scrolledToEdge` or not.
+- (void)setScrollViewScrolledToEdge:(BOOL)scrolledToEdge;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_GRID_TAB_GRID_BOTTOM_TOOLBAR_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.mm
index c27771b..4669b47 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_bottom_toolbar.mm
@@ -9,8 +9,10 @@
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_new_tab_button.h"
+#import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.h"
 #import "ios/chrome/browser/ui/thumb_strip/thumb_strip_feature.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
 
@@ -34,17 +36,30 @@
   UIBarButtonItem* _closeTabsButton;
   UIBarButtonItem* _shareButton;
   BOOL _undoActive;
+  BOOL _scrolledToEdge;
+  UIView* _scrolledToBottomBackgroundView;
+  UIView* _scrolledBackgroundView;
 }
 
 #pragma mark - UIView
 
 - (void)willMoveToSuperview:(UIView*)newSuperview {
+  [super willMoveToSuperview:newSuperview];
   // The first time this moves to a superview, perform the view setup.
   if (newSuperview && self.subviews.count == 0) {
     [self setupViews];
   }
 }
 
+- (void)didMoveToSuperview {
+  if (_scrolledBackgroundView) {
+    [self.superview.bottomAnchor
+        constraintEqualToAnchor:_scrolledBackgroundView.bottomAnchor]
+        .active = YES;
+  }
+  [super didMoveToSuperview];
+}
+
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
   [super traitCollectionDidChange:previousTraitCollection];
   if ((self.traitCollection.verticalSizeClass !=
@@ -178,6 +193,16 @@
   _largeNewTabButton.alpha = 1.0;
 }
 
+- (void)setScrollViewScrolledToEdge:(BOOL)scrolledToEdge {
+  if (!UseSymbols() || scrolledToEdge == _scrolledToEdge)
+    return;
+
+  _scrolledToEdge = scrolledToEdge;
+
+  _scrolledToBottomBackgroundView.hidden = !scrolledToEdge;
+  _scrolledBackgroundView.hidden = scrolledToEdge;
+}
+
 #pragma mark Close Tabs
 
 - (void)setCloseTabsButtonTarget:(id)target action:(SEL)action {
@@ -228,12 +253,7 @@
   _toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
   _toolbar.translatesAutoresizingMaskIntoConstraints = NO;
   if (UseSymbols()) {
-    UIToolbarAppearance* appearance = [[UIToolbarAppearance alloc] init];
-    appearance.backgroundColor =
-        [UIColor colorWithWhite:0 alpha:kToolbarBackgroundAlpha];
-    appearance.backgroundEffect = [UIBlurEffect
-        effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight];
-    _toolbar.standardAppearance = appearance;
+    [self createScrolledBackgrounds];
     _toolbar.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
   } else {
     _toolbar.barStyle = UIBarStyleBlack;
@@ -453,4 +473,32 @@
              UIUserInterfaceSizeClassCompact;
 }
 
+// Creates and configures the two background for the scrolled in the
+// middle/scrolled to the top states.
+- (void)createScrolledBackgrounds {
+  _scrolledToEdge = YES;
+
+  // Background when the content is scrolled to the middle.
+  _scrolledBackgroundView = CreateTabGridOverContentBackground();
+  _scrolledBackgroundView.hidden = YES;
+  _scrolledBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
+  [self addSubview:_scrolledBackgroundView];
+  AddSameConstraintsToSides(
+      self, _scrolledBackgroundView,
+      LayoutSides::kLeading | LayoutSides::kTop | LayoutSides::kTrailing);
+
+  // Background when the content is scrolled to the top.
+  _scrolledToBottomBackgroundView = CreateTabGridScrolledToEdgeBackground();
+  _scrolledToBottomBackgroundView.translatesAutoresizingMaskIntoConstraints =
+      NO;
+  [self addSubview:_scrolledToBottomBackgroundView];
+  AddSameConstraints(_scrolledBackgroundView, _scrolledToBottomBackgroundView);
+
+  // A non-nil UIImage has to be added in the background of the toolbar to avoid
+  // having an additional blur effect.
+  [_toolbar setBackgroundImage:[UIImage new]
+            forToolbarPosition:UIBarPositionAny
+                    barMetrics:UIBarMetricsDefault];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.h
index b2df0d2..dfbabf4 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.h
@@ -59,6 +59,10 @@
 // position change of the slider will be animated.
 - (void)setSelectedPage:(TabGridPage)selectedPage animated:(BOOL)animated;
 
+// Updates the appearance of the control, based on whether the content below it
+// is `scrolledToEdge` or not.
+- (void)setScrollViewScrolledToEdge:(BOOL)scrolledToEdge;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_GRID_TAB_GRID_PAGE_CONTROL_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.mm
index 5e3658a..b8df20c 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.mm
@@ -124,6 +124,7 @@
 // Alpha for the background view.
 const CGFloat kLegacyBackgroundAlpha = 0.3;
 const CGFloat kBackgroundAlpha = 0.15;
+const CGFloat kScrolledToTopBackgroundAlpha = 0.25;
 // Color for the regular tab count label and icons.
 const CGFloat kLegacySelectedColor = 0x3C4043;
 
@@ -177,6 +178,9 @@
   UIAccessibilityElement* _remoteAccessibilityElement;
 }
 
+// The grey background for all the segments.
+@property(nonatomic, weak) UIView* background;
+
 // Layout guides used to position segment-specific content.
 @property(nonatomic, weak) UILayoutGuide* incognitoGuide;
 @property(nonatomic, weak) UILayoutGuide* regularGuide;
@@ -225,6 +229,10 @@
 // Gesture recognizer used to handle taps. Owned by `self` as a UIView, so this
 // property is just a weak pointer to refer to it in some touch logic.
 @property(nonatomic, weak) UIGestureRecognizer* tapRecognizer;
+
+// Whether the content below is scrolled to the edge or displayed behind.
+@property(nonatomic, assign) BOOL scrolledToEdge;
+
 @end
 
 @implementation TabGridPageControl
@@ -279,6 +287,18 @@
   return self;
 }
 
+- (void)setScrollViewScrolledToEdge:(BOOL)scrolledToEdge {
+  if (!UseSymbols() || _scrolledToEdge == scrolledToEdge)
+    return;
+
+  _scrolledToEdge = scrolledToEdge;
+
+  CGFloat backgroundAlpha =
+      scrolledToEdge ? kScrolledToTopBackgroundAlpha : kBackgroundAlpha;
+  self.background.backgroundColor = [UIColor colorWithWhite:1
+                                                      alpha:backgroundAlpha];
+}
+
 #pragma mark - Public Properies
 
 - (void)setSelectedPage:(TabGridPage)selectedPage {
@@ -586,10 +606,12 @@
 - (void)setupViews {
   UIView* backgroundView = nil;
   if (UseSymbols()) {
+    self.scrolledToEdge = YES;
+
     backgroundView = [[UIView alloc]
         initWithFrame:CGRectMake(0, 0, kOverallWidth, kSegmentHeight)];
-    backgroundView.backgroundColor = [UIColor colorWithWhite:1
-                                                       alpha:kBackgroundAlpha];
+    backgroundView.backgroundColor =
+        [UIColor colorWithWhite:1 alpha:kScrolledToTopBackgroundAlpha];
 
   } else {
     backgroundView = [[TabGridPageControlBackground alloc] init];
@@ -609,6 +631,7 @@
     backgroundView.center =
         CGPointMake(kLegacyOverallWidth / 2.0, kLegacyOverallHeight / 2.0);
   }
+  self.background = backgroundView;
 
   // Set up the layout guides for the segments.
   UILayoutGuide* incognitoGuide = [[UILayoutGuide alloc] init];
@@ -729,7 +752,7 @@
 
   CGRect segmentRect;
   if (UseSymbols()) {
-    segmentRect = CGRectMake(0, 0, kSegmentWidth, kOverallHeight);
+    segmentRect = CGRectMake(0, 0, kSegmentWidth, kSegmentHeight);
   } else {
     segmentRect = CGRectMake(0, 0, kLegacySegmentWidth, kLegacyOverallHeight);
   }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.h
new file mode 100644
index 0000000..0cd7bce
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.h
@@ -0,0 +1,19 @@
+// 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 IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_GRID_TAB_GRID_TOOLBARS_UTILS_H_
+#define IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_GRID_TAB_GRID_TOOLBARS_UTILS_H_
+
+#import <UIKit/UIKit.h>
+
+// Returns a Toolbar background to be displayed when the content of the TabGrid
+// is scrolled to the edge of the toolbar.
+UIView* CreateTabGridScrolledToEdgeBackground();
+
+// Returns a Toolbar background to be displayed when the content of the TabGrid
+// is scrolled past the edge of the toolbar (content displayed below the
+// toolbar).
+UIView* CreateTabGridOverContentBackground();
+
+#endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_GRID_TAB_GRID_TOOLBARS_UTILS_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.mm
new file mode 100644
index 0000000..1749701
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.mm
@@ -0,0 +1,37 @@
+// 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 "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.h"
+
+#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h"
+#import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h"
+#import "ios/chrome/common/ui/util/constraints_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+UIView* CreateTabGridScrolledToEdgeBackground() {
+  UIView* scrolledToEdgeBackground = [[UIView alloc] init];
+  scrolledToEdgeBackground.backgroundColor =
+      [UIColor colorNamed:kGridBackgroundColor];
+
+  return scrolledToEdgeBackground;
+}
+
+UIView* CreateTabGridOverContentBackground() {
+  UIBlurEffect* effect = [UIBlurEffect
+      effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight];
+
+  UIVisualEffectView* visualEffectView =
+      [[UIVisualEffectView alloc] initWithEffect:effect];
+  UIView* background = [[UIView alloc] init];
+  background.backgroundColor = [UIColor colorWithWhite:0
+                                                 alpha:kToolbarBackgroundAlpha];
+  background.translatesAutoresizingMaskIntoConstraints = NO;
+  [visualEffectView.contentView addSubview:background];
+  AddSameConstraints(visualEffectView, background);
+
+  return visualEffectView;
+}
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.h
index 513188a..e4c08ad 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.h
@@ -23,6 +23,7 @@
 //   Remote page:    [                   PageControl             Done]
 //   Selection mode: [SelectAll        SelectedTabsCount         Done]
 @interface TabGridTopToolbar : UIToolbar
+
 // These components are publicly available to allow the user to set their
 // contents, visibility and actions.
 @property(nonatomic, strong, readonly) UIBarButtonItem* anchorItem;
@@ -60,6 +61,7 @@
 - (void)setCloseAllButtonEnabled:(BOOL)enabled;
 // use undo or closeAll text on the close all button based on `useUndo` value.
 - (void)useUndoCloseAll:(BOOL)useUndo;
+
 // Sets the `menu` displayed on tapping the Edit button.
 - (void)setEditButtonMenu:(UIMenu*)menu API_AVAILABLE(ios(14.0));
 // Set `enabled` on the Edit button.
@@ -75,6 +77,9 @@
 - (void)hide;
 // Recovers the normal appearance for tab grid transition animation.
 - (void)show;
+// Updates the appearance of the this toolbar, based on whether the content
+// below it is `scrolledToEdge` or not.
+- (void)setScrollViewScrolledToEdge:(BOOL)scrolledToEdge;
 
 @end
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm
index 3e72e90..244c92b 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm
@@ -8,10 +8,13 @@
 #import "base/feature_list.h"
 #import "base/ios/ios_util.h"
 #import "ios/chrome/browser/ui/icons/symbols.h"
+#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.h"
+#import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_toolbars_utils.h"
 #import "ios/chrome/browser/ui/thumb_strip/thumb_strip_feature.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
 
@@ -54,6 +57,10 @@
   UIView* _searchBarView;
 
   BOOL _undoActive;
+
+  BOOL _scrolledToEdge;
+  UIView* _scrolledToTopBackgroundView;
+  UIView* _scrolledBackgroundView;
 }
 
 - (UIBarButtonItem*)anchorItem {
@@ -200,6 +207,17 @@
   self.pageControl.alpha = 1.0;
 }
 
+- (void)setScrollViewScrolledToEdge:(BOOL)scrolledToEdge {
+  if (!UseSymbols() || scrolledToEdge == _scrolledToEdge)
+    return;
+
+  _scrolledToEdge = scrolledToEdge;
+
+  _scrolledToTopBackgroundView.hidden = !scrolledToEdge;
+  _scrolledBackgroundView.hidden = scrolledToEdge;
+  [_pageControl setScrollViewScrolledToEdge:scrolledToEdge];
+}
+
 #pragma mark Edit Button
 
 - (void)setEditButtonMenu:(UIMenu*)menu API_AVAILABLE(ios(14.0)) {
@@ -217,12 +235,22 @@
 }
 
 - (void)willMoveToSuperview:(UIView*)newSuperview {
+  [super willMoveToSuperview:newSuperview];
   // The first time this moves to a superview, perform the view setup.
   if (newSuperview && self.subviews.count == 0) {
     [self setupViews];
   }
 }
 
+- (void)didMoveToSuperview {
+  if (_scrolledBackgroundView) {
+    [self.superview.topAnchor
+        constraintEqualToAnchor:_scrolledBackgroundView.topAnchor]
+        .active = YES;
+  }
+  [super didMoveToSuperview];
+}
+
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
   [super traitCollectionDidChange:previousTraitCollection];
   [self setItemsForTraitCollection:self.traitCollection];
@@ -362,6 +390,7 @@
   self.translatesAutoresizingMaskIntoConstraints = NO;
   if (UseSymbols()) {
     self.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
+    [self createScrolledBackgrounds];
   } else {
     self.barStyle = UIBarStyleBlack;
     self.translucent = YES;
@@ -369,7 +398,7 @@
   self.delegate = self;
   [self setShadowImage:[[UIImage alloc] init]
       forToolbarPosition:UIBarPositionAny];
-  if (base::ios::HasDynamicIsland()) {
+  if (!UseSymbols() && base::ios::HasDynamicIsland()) {
     // Do this to make the toolbar transparent instead of translucent.
     [self setBackgroundImage:[UIImage new]
           forToolbarPosition:UIToolbarPositionAny
@@ -384,6 +413,7 @@
   // The segmented control has an intrinsic size.
   _pageControl = [[TabGridPageControl alloc] init];
   _pageControl.translatesAutoresizingMaskIntoConstraints = NO;
+  [_pageControl setScrollViewScrolledToEdge:_scrolledToEdge];
   _pageControlItem = [[UIBarButtonItem alloc] initWithCustomView:_pageControl];
 
   _doneButton = [[UIBarButtonItem alloc] init];
@@ -483,6 +513,33 @@
   [self setItemsForTraitCollection:self.traitCollection];
 }
 
+// Creates and configures the two background for the scrolled in the
+// middle/scrolled to the top states.
+- (void)createScrolledBackgrounds {
+  _scrolledToEdge = YES;
+
+  // Background when the content is scrolled to the middle.
+  _scrolledBackgroundView = CreateTabGridOverContentBackground();
+  _scrolledBackgroundView.hidden = YES;
+  _scrolledBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
+  [self addSubview:_scrolledBackgroundView];
+  AddSameConstraintsToSides(
+      self, _scrolledBackgroundView,
+      LayoutSides::kLeading | LayoutSides::kBottom | LayoutSides::kTrailing);
+
+  // Background when the content is scrolled to the top.
+  _scrolledToTopBackgroundView = CreateTabGridScrolledToEdgeBackground();
+  _scrolledToTopBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
+  [self addSubview:_scrolledToTopBackgroundView];
+  AddSameConstraints(_scrolledBackgroundView, _scrolledToTopBackgroundView);
+
+  // A non-nil UIImage has to be added in the background of the toolbar to avoid
+  // having an additional blur effect.
+  [self setBackgroundImage:[UIImage new]
+        forToolbarPosition:UIBarPositionAny
+                barMetrics:UIBarMetricsDefault];
+}
+
 // Returns YES if should use compact bottom toolbar layout.
 - (BOOL)shouldUseCompactLayout:(UITraitCollection*)traitCollection {
   return traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular &&
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
index 6f2a9273..c96bde84 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
@@ -19,10 +19,12 @@
 #import "ios/chrome/browser/ui/default_promo/default_browser_utils.h"
 #import "ios/chrome/browser/ui/gestures/view_controller_trait_collection_observer.h"
 #import "ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.h"
+#import "ios/chrome/browser/ui/icons/symbols.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/keyboard/features.h"
 #import "ios/chrome/browser/ui/menu/action_factory.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_ui_delegate.h"
 #import "ios/chrome/browser/ui/tab_switcher/pinned_tabs/features.h"
 #import "ios/chrome/browser/ui/tab_switcher/pinned_tabs/pinned_tabs_constants.h"
 #import "ios/chrome/browser/ui/tab_switcher/pinned_tabs/pinned_tabs_view_controller.h"
@@ -131,6 +133,7 @@
 @interface TabGridViewController () <DisabledTabViewControllerDelegate,
                                      GridViewControllerDelegate,
                                      LayoutSwitcher,
+                                     RecentTabsTableViewControllerUIDelegate,
                                      SuggestedActionsDelegate,
                                      UIGestureRecognizerDelegate,
                                      UIScrollViewAccessibilityDelegate,
@@ -1074,6 +1077,7 @@
     [self.pinnedTabsViewController
         pinnedTabsAvailable:isTabGridPageRegularTabs];
   }
+  [self updateToolbarsAppearance];
 }
 
 // Sets the value of `currentPage`, adjusting the position of the scroll view
@@ -1275,16 +1279,17 @@
 // Adds the remote tabs view controller as a contained view controller, and
 // sets constraints.
 - (void)setupRemoteTabsViewController {
+  RecentTabsTableViewController* viewController = self.remoteTabsViewController;
+  viewController.UIDelegate = self;
+
   // TODO(crbug.com/804589) : Dark style on remote tabs.
   // The styler must be set before the view controller is loaded.
   ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
   styler.tableViewBackgroundColor = [UIColor colorNamed:kGridBackgroundColor];
-  self.remoteTabsViewController.overrideUserInterfaceStyle =
-      UIUserInterfaceStyleDark;
-  self.remoteTabsViewController.styler = styler;
+  viewController.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
+  viewController.styler = styler;
 
   UIView* contentView = self.scrollContentView;
-  RecentTabsTableViewController* viewController = self.remoteTabsViewController;
   viewController.view.translatesAutoresizingMaskIntoConstraints = NO;
   [self addChildViewController:viewController];
   [contentView addSubview:viewController.view];
@@ -1376,7 +1381,7 @@
 // Adds the top toolbar and sets constraints.
 - (void)setupTopToolbar {
   UIVisualEffectView* topToolbarBlurView;
-  if (base::ios::HasDynamicIsland()) {
+  if (!UseSymbols() && base::ios::HasDynamicIsland()) {
     UIBlurEffect* blurEffect =
         [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
     topToolbarBlurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
@@ -1420,7 +1425,7 @@
     [topToolbar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]
   ]];
 
-  if (base::ios::HasDynamicIsland()) {
+  if (!UseSymbols() && base::ios::HasDynamicIsland()) {
     [NSLayoutConstraint activateConstraints:@[
       [topToolbarBlurView.topAnchor
           constraintEqualToAnchor:self.view.topAnchor],
@@ -2021,6 +2026,33 @@
       }];
 }
 
+// Updates the appearance of the toolbars based on the scroll position of the
+// currently active Grid.
+- (void)updateToolbarsAppearance {
+  UIScrollView* scrollView;
+  switch (self.currentPage) {
+    case TabGridPageIncognitoTabs:
+      scrollView = self.incognitoTabsViewController.gridView;
+      break;
+    case TabGridPageRegularTabs:
+      scrollView = self.regularTabsViewController.gridView;
+      break;
+    case TabGridPageRemoteTabs:
+      scrollView = self.remoteTabsViewController.tableView;
+      break;
+  }
+
+  BOOL gridScrolledToTop =
+      scrollView.contentOffset.y <= -scrollView.adjustedContentInset.top;
+  [self.topToolbar setScrollViewScrolledToEdge:gridScrolledToTop];
+
+  CGFloat scrollableHeight = scrollView.contentSize.height +
+                             scrollView.adjustedContentInset.bottom -
+                             scrollView.bounds.size.height;
+  BOOL gridScrolledToBottom = scrollView.contentOffset.y >= scrollableHeight;
+  [self.bottomToolbar setScrollViewScrolledToEdge:gridScrolledToBottom];
+}
+
 #pragma mark UIGestureRecognizerDelegate
 
 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
@@ -2097,6 +2129,13 @@
   }
 }
 
+#pragma mark - RecentTabsTableViewControllerUIDelegate
+
+- (void)recentTabsScrollViewDidScroll:
+    (RecentTabsTableViewController*)recentTabsTableViewController {
+  [self updateToolbarsAppearance];
+}
+
 #pragma mark - SuggestedActionsDelegate
 
 - (void)fetchSearchHistoryResultsCountForText:(NSString*)searchText
@@ -2335,6 +2374,11 @@
   }
 }
 
+- (void)gridViewControllerScrollViewDidScroll:
+    (GridViewController*)gridViewController {
+  [self updateToolbarsAppearance];
+}
+
 #pragma mark - Control actions
 
 - (void)doneButtonTapped:(id)sender {
diff --git a/ios/chrome/browser/ui/tabs/background_tab_animation_view.h b/ios/chrome/browser/ui/tabs/background_tab_animation_view.h
index 9ed550b..1aca76e 100644
--- a/ios/chrome/browser/ui/tabs/background_tab_animation_view.h
+++ b/ios/chrome/browser/ui/tabs/background_tab_animation_view.h
@@ -7,19 +7,25 @@
 
 #import <UIKit/UIKit.h>
 
+@class LayoutGuideCenter;
+
 // View containing a link image and a shadow. Used to notify the user that a new
 // tab has been opened in background.
 @interface BackgroundTabAnimationView : UIView
 
+// The layout guide center to use to refer to the tab grid button.
+@property(nonatomic, strong) LayoutGuideCenter* layoutGuideCenter;
+
 - (instancetype)initWithFrame:(CGRect)frame
                     incognito:(BOOL)incognito NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
 
-// Starts an Open In New Tab animation in `parentView`, from `originPoint` with
-// a `completion` block. The named layout guide for the TabGrid button should be
-// accessible from `parentView`. `originPoint` should be in window coordinates.
+// Starts an Open In New Tab animation in the superview, from `originPoint` with
+// a `completion` block. `originPoint` should be in window coordinates.
+// Internally, kTabSwitcherGuide is used to determine the location of the tab
+// grid button.
 - (void)animateFrom:(CGPoint)originPoint
     toTabGridButtonWithCompletion:(void (^)())completion;
 
diff --git a/ios/chrome/browser/ui/tabs/background_tab_animation_view.mm b/ios/chrome/browser/ui/tabs/background_tab_animation_view.mm
index 99c0897..2a011ab 100644
--- a/ios/chrome/browser/ui/tabs/background_tab_animation_view.mm
+++ b/ios/chrome/browser/ui/tabs/background_tab_animation_view.mm
@@ -6,9 +6,9 @@
 
 #import "base/check.h"
 #import "ios/chrome/browser/ui/util/animation_util.h"
-#import "ios/chrome/browser/ui/util/named_guide.h"
-#import "ios/chrome/browser/ui/util/named_guide_util.h"
+#import "ios/chrome/browser/ui/util/layout_guide_names.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/browser/ui/util/util_swift.h"
 #import "ios/chrome/common/material_timing.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
@@ -140,14 +140,13 @@
 // Returns the destination point for the animation, in the superview
 // coordinates.
 - (CGPoint)destinationPoint {
+  DCHECK(self.layoutGuideCenter);
   UILayoutGuide* tabGridButtonLayoutGuide =
-      [NamedGuide guideWithName:kTabSwitcherGuide view:self.superview];
+      [self.layoutGuideCenter makeLayoutGuideNamed:kTabSwitcherGuide];
+  // Note: adding to the superview, as adding to `self` breaks its layout.
+  [self.superview addLayoutGuide:tabGridButtonLayoutGuide];
   CGRect frame = [tabGridButtonLayoutGuide layoutFrame];
-  CGPoint tabGridButtonCenter =
-      CGPointMake(frame.origin.x + frame.size.width / 2,
-                  frame.origin.y + frame.size.height / 2);
-  return [self.superview convertPoint:tabGridButtonCenter
-                             fromView:tabGridButtonLayoutGuide.owningView];
+  return CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame));
 }
 
 // Returns the animation duration, based on the `parentSize` and the `yDiff` and
diff --git a/ios/chrome/features.gni b/ios/chrome/features.gni
index e0ad5ee7..70b6b61 100644
--- a/ios/chrome/features.gni
+++ b/ios/chrome/features.gni
@@ -8,6 +8,11 @@
   # MaterialComponents is not build as a framework.
   ios_chrome_links_with_material_components_framework = true
 
+  # Controls whether Chrome links with Lottie.framework or gets the
+  # implementation from its downstream provider. Ignored if Lottie is
+  # not build as a framework.
+  ios_chrome_links_with_lottie_framework = false
+
   # Enable MetricKit in Chrome to collect runtime data.
   ios_enable_metrickit = false
 
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
index 6d082bb5..15908e23 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
@@ -88,6 +88,7 @@
     id<SystemIdentity> identity,
     UIViewController* view_controller,
     BOOL animated) {
+  NOTREACHED() << "Subclasses must override this";
   return nil;
 }
 
@@ -96,6 +97,7 @@
     id<SystemIdentity> identity,
     UIViewController* view_controller,
     BOOL animated) {
+  NOTREACHED() << "Subclasses must override this";
   return nil;
 }
 
@@ -106,14 +108,20 @@
 }
 
 void ChromeIdentityService::IterateOverIdentities(
-    SystemIdentityIteratorCallback) {}
+    SystemIdentityIteratorCallback) {
+  // TODO(crbug.com/1392742): Need to add NOTREACHED().
+}
 
 void ChromeIdentityService::ForgetIdentity(id<SystemIdentity> identity,
-                                           ForgetIdentityCallback callback) {}
+                                           ForgetIdentityCallback callback) {
+  NOTREACHED() << "Subclasses must override this";
+}
 
 void ChromeIdentityService::GetAccessToken(id<SystemIdentity> identity,
                                            const std::set<std::string>& scopes,
-                                           AccessTokenCallback callback) {}
+                                           AccessTokenCallback callback) {
+  NOTREACHED() << "Subclasses must override this";
+}
 
 void ChromeIdentityService::GetAccessToken(id<SystemIdentity> identity,
                                            const std::string& client_id,
@@ -121,18 +129,20 @@
                                            AccessTokenCallback callback) {}
 
 void ChromeIdentityService::GetAvatarForIdentity(id<SystemIdentity> identity) {
-  NOTREACHED();
+  NOTREACHED() << "Subclasses must override this";
 }
 
 UIImage* ChromeIdentityService::GetCachedAvatarForIdentity(
     id<SystemIdentity> identity) {
-  NOTREACHED();
+  NOTREACHED() << "Subclasses must override this";
   return nil;
 }
 
 void ChromeIdentityService::GetHostedDomainForIdentity(
     id<SystemIdentity> identity,
-    GetHostedDomainCallback callback) {}
+    GetHostedDomainCallback callback) {
+  NOTREACHED() << "Subclasses must override this";
+}
 
 NSString* ChromeIdentityService::GetCachedHostedDomainForIdentity(
     id<SystemIdentity> identity) {
@@ -168,17 +178,20 @@
 
 MDMDeviceStatus ChromeIdentityService::GetMDMDeviceStatus(
     NSDictionary* user_info) {
+  NOTREACHED() << "Subclasses must override this";
   return 0;
 }
 
 bool ChromeIdentityService::HandleMDMNotification(id<SystemIdentity> identity,
                                                   NSDictionary* user_info,
                                                   MDMStatusCallback callback) {
+  NOTREACHED() << "Subclasses must override this";
   return false;
 }
 
 bool ChromeIdentityService::IsMDMError(id<SystemIdentity> identity,
                                        NSError* error) {
+  NOTREACHED() << "Subclasses must override this";
   return false;
 }
 
diff --git a/ios/third_party/lottie/BUILD.gn b/ios/third_party/lottie/BUILD.gn
new file mode 100644
index 0000000..b6ea5f6
--- /dev/null
+++ b/ios/third_party/lottie/BUILD.gn
@@ -0,0 +1,214 @@
+import("//build/config/ios/ios_sdk.gni")
+import("//build/config/ios/rules.gni")
+
+_lottie_public_headers = [
+  # $ cd src/ios/third_party/lottie
+  # $ find src -path 'src/lottie-ios/Classes/PublicHeaders/*.h'  -a \! -path '*Test*'|\sed -e
+  #   's:\(.*\):  "\1",:'|sort -u
+
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimatedControl.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimatedSwitch.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimationCache.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimationTransitionController.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimationView.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimationView_Compat.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTBlockCallback.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTCacheProvider.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTComposition.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTInterpolatorCallback.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTKeypath.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTValueCallback.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTValueDelegate.h",
+  "src/lottie-ios/Classes/PublicHeaders/Lottie.h",
+]
+
+_lottie_include_dirs = [
+  # List generated by the following commands:
+  # $ cd src/ios/third_party/lottie
+  # $ find src -path 'src/lottie-ios/Classes/**/*.h' -a \! -path '*Test*'|\
+  #   sed -e 's:\(.*\)/[^/]*:  "\1",:'|sort -u
+
+  "src/lottie-ios/Classes/AnimatableLayers",
+  "src/lottie-ios/Classes/AnimatableProperties",
+  "src/lottie-ios/Classes/Extensions",
+  "src/lottie-ios/Classes/MacCompatibility",
+  "src/lottie-ios/Classes/Models",
+  "src/lottie-ios/Classes/Private",
+  "src/lottie-ios/Classes/PublicHeaders",
+  "src/lottie-ios/Classes/RenderSystem",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes",
+  "src/lottie-ios/Classes/RenderSystem/ManipulatorNodes",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes",
+]
+
+_lottie_sources = [
+  # List generated by the following commands:
+  # $ cd src/ios/third_party/material_components_ios
+  # $ find src -path 'src/lottie-ios/Classes/**/*.[hm]' -a \! -path '*Test*'|\
+  #   sed -e 's:\(.*\):  "\1",:'|sort -u
+
+  "src/lottie-ios/Classes/AnimatableLayers/LOTCompositionContainer.h",
+  "src/lottie-ios/Classes/AnimatableLayers/LOTCompositionContainer.m",
+  "src/lottie-ios/Classes/AnimatableLayers/LOTLayerContainer.h",
+  "src/lottie-ios/Classes/AnimatableLayers/LOTLayerContainer.m",
+  "src/lottie-ios/Classes/AnimatableLayers/LOTMaskContainer.h",
+  "src/lottie-ios/Classes/AnimatableLayers/LOTMaskContainer.m",
+  "src/lottie-ios/Classes/AnimatableProperties/LOTBezierData.h",
+  "src/lottie-ios/Classes/AnimatableProperties/LOTBezierData.m",
+  "src/lottie-ios/Classes/AnimatableProperties/LOTKeyframe.h",
+  "src/lottie-ios/Classes/AnimatableProperties/LOTKeyframe.m",
+  "src/lottie-ios/Classes/Extensions/CGGeometry+LOTAdditions.h",
+  "src/lottie-ios/Classes/Extensions/CGGeometry+LOTAdditions.m",
+  "src/lottie-ios/Classes/Extensions/LOTBezierPath.h",
+  "src/lottie-ios/Classes/Extensions/LOTBezierPath.m",
+  "src/lottie-ios/Classes/Extensions/LOTHelpers.h",
+  "src/lottie-ios/Classes/Extensions/LOTRadialGradientLayer.h",
+  "src/lottie-ios/Classes/Extensions/LOTRadialGradientLayer.m",
+  "src/lottie-ios/Classes/Extensions/UIColor+Expanded.h",
+  "src/lottie-ios/Classes/Extensions/UIColor+Expanded.m",
+  "src/lottie-ios/Classes/MacCompatibility/CALayer+Compat.h",
+  "src/lottie-ios/Classes/MacCompatibility/CALayer+Compat.m",
+  "src/lottie-ios/Classes/MacCompatibility/LOTPlatformCompat.h",
+  "src/lottie-ios/Classes/MacCompatibility/NSValue+Compat.h",
+  "src/lottie-ios/Classes/MacCompatibility/NSValue+Compat.m",
+  "src/lottie-ios/Classes/MacCompatibility/UIBezierPath.h",
+  "src/lottie-ios/Classes/MacCompatibility/UIBezierPath.m",
+  "src/lottie-ios/Classes/MacCompatibility/UIColor.h",
+  "src/lottie-ios/Classes/MacCompatibility/UIColor.m",
+  "src/lottie-ios/Classes/Models/LOTAsset.h",
+  "src/lottie-ios/Classes/Models/LOTAsset.m",
+  "src/lottie-ios/Classes/Models/LOTAssetGroup.h",
+  "src/lottie-ios/Classes/Models/LOTAssetGroup.m",
+  "src/lottie-ios/Classes/Models/LOTLayer.h",
+  "src/lottie-ios/Classes/Models/LOTLayer.m",
+  "src/lottie-ios/Classes/Models/LOTLayerGroup.h",
+  "src/lottie-ios/Classes/Models/LOTLayerGroup.m",
+  "src/lottie-ios/Classes/Models/LOTMask.h",
+  "src/lottie-ios/Classes/Models/LOTMask.m",
+  "src/lottie-ios/Classes/Models/LOTModels.h",
+  "src/lottie-ios/Classes/Models/LOTShapeCircle.h",
+  "src/lottie-ios/Classes/Models/LOTShapeCircle.m",
+  "src/lottie-ios/Classes/Models/LOTShapeFill.h",
+  "src/lottie-ios/Classes/Models/LOTShapeFill.m",
+  "src/lottie-ios/Classes/Models/LOTShapeGradientFill.h",
+  "src/lottie-ios/Classes/Models/LOTShapeGradientFill.m",
+  "src/lottie-ios/Classes/Models/LOTShapeGroup.h",
+  "src/lottie-ios/Classes/Models/LOTShapeGroup.m",
+  "src/lottie-ios/Classes/Models/LOTShapePath.h",
+  "src/lottie-ios/Classes/Models/LOTShapePath.m",
+  "src/lottie-ios/Classes/Models/LOTShapeRectangle.h",
+  "src/lottie-ios/Classes/Models/LOTShapeRectangle.m",
+  "src/lottie-ios/Classes/Models/LOTShapeRepeater.h",
+  "src/lottie-ios/Classes/Models/LOTShapeRepeater.m",
+  "src/lottie-ios/Classes/Models/LOTShapeStar.h",
+  "src/lottie-ios/Classes/Models/LOTShapeStar.m",
+  "src/lottie-ios/Classes/Models/LOTShapeStroke.h",
+  "src/lottie-ios/Classes/Models/LOTShapeStroke.m",
+  "src/lottie-ios/Classes/Models/LOTShapeTransform.h",
+  "src/lottie-ios/Classes/Models/LOTShapeTransform.m",
+  "src/lottie-ios/Classes/Models/LOTShapeTrimPath.h",
+  "src/lottie-ios/Classes/Models/LOTShapeTrimPath.m",
+  "src/lottie-ios/Classes/Private/LOTAnimatedControl.m",
+  "src/lottie-ios/Classes/Private/LOTAnimatedSwitch.m",
+  "src/lottie-ios/Classes/Private/LOTAnimationCache.m",
+  "src/lottie-ios/Classes/Private/LOTAnimationTransitionController.m",
+  "src/lottie-ios/Classes/Private/LOTAnimationView.m",
+  "src/lottie-ios/Classes/Private/LOTAnimationView_Internal.h",
+  "src/lottie-ios/Classes/Private/LOTBlockCallback.m",
+  "src/lottie-ios/Classes/Private/LOTCacheProvider.m",
+  "src/lottie-ios/Classes/Private/LOTComposition.m",
+  "src/lottie-ios/Classes/Private/LOTInterpolatorCallback.m",
+  "src/lottie-ios/Classes/Private/LOTKeypath.m",
+  "src/lottie-ios/Classes/Private/LOTValueCallback.m",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimatedControl.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimatedSwitch.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimationCache.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimationTransitionController.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimationView.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTAnimationView_Compat.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTBlockCallback.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTCacheProvider.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTComposition.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTInterpolatorCallback.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTKeypath.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTValueCallback.h",
+  "src/lottie-ios/Classes/PublicHeaders/LOTValueDelegate.h",
+  "src/lottie-ios/Classes/PublicHeaders/Lottie.h",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTCircleAnimator.h",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTCircleAnimator.m",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTPathAnimator.h",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTPathAnimator.m",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTPolygonAnimator.h",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTPolygonAnimator.m",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTPolystarAnimator.h",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTPolystarAnimator.m",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTRoundedRectAnimator.h",
+  "src/lottie-ios/Classes/RenderSystem/AnimatorNodes/LOTRoundedRectAnimator.m",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTArrayInterpolator.h",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTArrayInterpolator.m",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTColorInterpolator.h",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTColorInterpolator.m",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTNumberInterpolator.h",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTNumberInterpolator.m",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTPathInterpolator.h",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTPathInterpolator.m",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTPointInterpolator.h",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTPointInterpolator.m",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTSizeInterpolator.h",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTSizeInterpolator.m",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTTransformInterpolator.h",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTTransformInterpolator.m",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTValueInterpolator.h",
+  "src/lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTValueInterpolator.m",
+  "src/lottie-ios/Classes/RenderSystem/LOTAnimatorNode.h",
+  "src/lottie-ios/Classes/RenderSystem/LOTAnimatorNode.m",
+  "src/lottie-ios/Classes/RenderSystem/LOTRenderNode.h",
+  "src/lottie-ios/Classes/RenderSystem/LOTRenderNode.m",
+  "src/lottie-ios/Classes/RenderSystem/ManipulatorNodes/LOTTrimPathNode.h",
+  "src/lottie-ios/Classes/RenderSystem/ManipulatorNodes/LOTTrimPathNode.m",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTFillRenderer.h",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTFillRenderer.m",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTGradientFillRender.h",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTGradientFillRender.m",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTRenderGroup.h",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTRenderGroup.m",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTRepeaterRenderer.h",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTRepeaterRenderer.m",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTStrokeRenderer.h",
+  "src/lottie-ios/Classes/RenderSystem/RenderNodes/LOTStrokeRenderer.m",
+]
+
+config("config") {
+  visibility = [ ":*" ]
+  include_dirs = _lottie_include_dirs
+}
+
+ios_framework_bundle("lottie") {
+  sources = _lottie_sources
+
+  info_plist = "Info.plist"
+  output_name = "Lottie"
+  public_headers = _lottie_public_headers
+
+  frameworks = [
+    "CoreGraphics.framework",
+    "Foundation.framework",
+    "CoreFoundation.framework",
+    "UIKit.framework",
+    "QuartzCore.framework",
+    "CoreVideo.framework",
+    "GLKit.framework",
+  ]
+
+  configs -= [
+    "//build/config/compiler:chromium_code",
+    "//build/config/gcc:symbol_visibility_hidden",
+  ]
+  configs += [
+    ":config",
+    "//build/config/compiler:enable_arc",
+    "//build/config/compiler:no_chromium_code",
+    "//build/config/gcc:symbol_visibility_default",
+  ]
+}
diff --git a/ios/third_party/lottie/Info.plist b/ios/third_party/lottie/Info.plist
new file mode 100644
index 0000000..449c5cc4
--- /dev/null
+++ b/ios/third_party/lottie/Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleVersion</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleIdentifier</key>
+       <string>${BUNDLE_IDENTIFIER}</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+</dict>
+</plist>
diff --git a/ios/third_party/lottie/LICENSE b/ios/third_party/lottie/LICENSE
new file mode 100644
index 0000000..13f1254
--- /dev/null
+++ b/ios/third_party/lottie/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2018 Airbnb, Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/ios/third_party/lottie/OWNERS b/ios/third_party/lottie/OWNERS
new file mode 100644
index 0000000..ae82009
--- /dev/null
+++ b/ios/third_party/lottie/OWNERS
@@ -0,0 +1,2 @@
+rohitrao@chromium.org
+sdefresne@chromium.org
diff --git a/ios/third_party/lottie/README.chromium b/ios/third_party/lottie/README.chromium
new file mode 100644
index 0000000..5825ff9
--- /dev/null
+++ b/ios/third_party/lottie/README.chromium
@@ -0,0 +1,13 @@
+Name: lottie_ios
+URL: https://github.com/airbnb/lottie-ios.git
+Version: 2.5.2
+License: Apache 2.0
+License File: LICENSE
+Security critical: yes
+
+Description:
+Lottie is a cross-platform library for iOS, macOS, tvOS, Android, and Web that
+natively renders vector-based animations and art in realtime with minimal code.
+Lottie loads and renders animations and vectors exported in the bodymovin JSON
+format. Bodymovin JSON can be created and exported from After Effects with
+bodymovin, Sketch with Lottie Sketch Export, and from Haiku.
diff --git a/media/mojo/clients/win/media_foundation_renderer_client.cc b/media/mojo/clients/win/media_foundation_renderer_client.cc
index 3094cf4..be97084 100644
--- a/media/mojo/clients/win/media_foundation_renderer_client.cc
+++ b/media/mojo/clients/win/media_foundation_renderer_client.cc
@@ -204,6 +204,18 @@
   DVLOG_FUNC(1) << "status=" << status;
 
   SignalMediaPlayingStateChange(false);
+
+  // When hardware context reset happens, presenting the `dcomp_video_frame_`
+  // could cause issues like black screen flash (see crbug.com/1384544).
+  // Render a black frame to avoid this issue. This is fine since the player
+  // is already in an error state and `this` will be recreated.
+  if (status == PIPELINE_ERROR_HARDWARE_CONTEXT_RESET && dcomp_video_frame_ &&
+      !IsFrameServerMode()) {
+    dcomp_video_frame_.reset();
+    auto black_frame = media::VideoFrame::CreateBlackFrame(natural_size_);
+    sink_->PaintSingleFrame(black_frame, true);
+  }
+
   // Do not call MediaFoundationRenderer::ReportErrorReason() since it should've
   // already been reported in MediaFoundationRenderer.
   client_->OnError(status);
@@ -542,6 +554,7 @@
 
   if (cdm_context_) {
     video_frame->metadata().protected_video = true;
+    video_frame->metadata().hw_protected = true;
   } else {
     DCHECK(SupportMediaFoundationClearPlayback());
     // This video frame is for clear content: setup observation of the mailbox
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index 1d348b1..6fc8ef14 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -63,15 +63,12 @@
 
 gfx::ProtectedVideoType ProtectedVideoTypeFromMetadata(
     const VideoFrameMetadata& metadata) {
-  gfx::ProtectedVideoType video_type = gfx::ProtectedVideoType::kClear;
-  if (metadata.protected_video) {
-    if (metadata.hw_protected) {
-      video_type = gfx::ProtectedVideoType::kHardwareProtected;
-    } else {
-      video_type = gfx::ProtectedVideoType::kSoftwareProtected;
-    }
+  if (!metadata.protected_video) {
+    return gfx::ProtectedVideoType::kClear;
   }
-  return video_type;
+
+  return metadata.hw_protected ? gfx::ProtectedVideoType::kHardwareProtected
+                               : gfx::ProtectedVideoType::kSoftwareProtected;
 }
 
 VideoFrameResourceType ExternalResourceTypeForHardwarePlanes(
diff --git a/net/base/network_anonymization_key.h b/net/base/network_anonymization_key.h
index a5f47e6..d1fb4b5f 100644
--- a/net/base/network_anonymization_key.h
+++ b/net/base/network_anonymization_key.h
@@ -101,8 +101,8 @@
                     other.is_cross_site_, other.nonce_);
   }
 
-  // Creates a NetworkAnonymizationKey from a NetworkAnonymizationKey. This is
-  // possible because a NetworkAnonymizationKey must always be more granular
+  // Creates a NetworkAnonymizationKey from a NetworkIsolationKey. This is
+  // possible because a NetworkIsolationKey must always be more granular
   // than a NetworkAnonymizationKey.
   static NetworkAnonymizationKey CreateFromNetworkIsolationKey(
       const net::NetworkIsolationKey& network_isolation_key);
diff --git a/net/first_party_sets/global_first_party_sets.cc b/net/first_party_sets/global_first_party_sets.cc
index fe7e738..e6dc57cc 100644
--- a/net/first_party_sets/global_first_party_sets.cc
+++ b/net/first_party_sets/global_first_party_sets.cc
@@ -88,25 +88,20 @@
           public_sets_version.IsValid()
               ? std::move(aliases)
               : base::flat_map<SchemefulSite, SchemefulSite>(),
-          /*manual_sets=*/{},
           FirstPartySetsContextConfig()) {}
 
 GlobalFirstPartySets::GlobalFirstPartySets(
     base::Version public_sets_version,
     base::flat_map<SchemefulSite, FirstPartySetEntry> entries,
     base::flat_map<SchemefulSite, SchemefulSite> aliases,
-    base::flat_map<SchemefulSite, FirstPartySetEntry> manual_sets,
     FirstPartySetsContextConfig manual_config)
     : public_sets_version_(std::move(public_sets_version)),
       entries_(std::move(entries)),
       aliases_(std::move(aliases)),
-      manual_sets_(std::move(manual_sets)),
       manual_config_(std::move(manual_config)) {
   // `aliases_` can only be nonempty if `entries_` is also nonempty.
   if (!aliases_.empty())
     DCHECK(!entries_.empty());
-
-  DCHECK_EQ(manual_sets_.empty(), manual_config_.empty());
 }
 
 GlobalFirstPartySets::GlobalFirstPartySets(GlobalFirstPartySets&&) = default;
@@ -116,10 +111,9 @@
 GlobalFirstPartySets::~GlobalFirstPartySets() = default;
 
 bool GlobalFirstPartySets::operator==(const GlobalFirstPartySets& other) const {
-  return std::tie(public_sets_version_, entries_, aliases_, manual_sets_,
-                  manual_config_) ==
+  return std::tie(public_sets_version_, entries_, aliases_, manual_config_) ==
          std::tie(other.public_sets_version_, other.entries_, other.aliases_,
-                  other.manual_sets_, other.manual_config_);
+                  other.manual_config_);
 }
 
 bool GlobalFirstPartySets::operator!=(const GlobalFirstPartySets& other) const {
@@ -128,7 +122,7 @@
 
 GlobalFirstPartySets GlobalFirstPartySets::Clone() const {
   return GlobalFirstPartySets(public_sets_version_, entries_, aliases_,
-                              manual_sets_, manual_config_.Clone());
+                              manual_config_.Clone());
 }
 
 absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
@@ -236,13 +230,18 @@
 void GlobalFirstPartySets::ApplyManuallySpecifiedSet(
     const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries) {
   DCHECK(manual_config_.empty());
-  manual_sets_ = manual_entries;
   // We handle the manually-specified set the same way as we handle
   // replacement enterprise policy sets.
   manual_config_ = ComputeConfig(
       /*replacement_sets=*/{manual_entries}, /*addition_sets=*/{});
 }
 
+void GlobalFirstPartySets::UnsafeSetManualConfig(
+    FirstPartySetsContextConfig manual_config) {
+  DCHECK(manual_config_.empty());
+  manual_config_ = std::move(manual_config);
+}
+
 FirstPartySetsContextConfig GlobalFirstPartySets::ComputeConfig(
     const std::vector<SingleSet>& replacement_sets,
     const std::vector<SingleSet>& addition_sets) const {
@@ -439,6 +438,13 @@
   return true;
 }
 
+bool GlobalFirstPartySets::ForEachManualConfigEntry(
+    base::FunctionRef<bool(const SchemefulSite&,
+                           const absl::optional<FirstPartySetEntry>&)> f)
+    const {
+  return manual_config_.ForEachCustomizationEntry(f);
+}
+
 bool GlobalFirstPartySets::ForEachEffectiveSetEntry(
     const FirstPartySetsContextConfig& config,
     base::FunctionRef<bool(const SchemefulSite&, const FirstPartySetEntry&)> f)
@@ -492,10 +498,6 @@
   for (const auto& [alias, canonical] : sets.aliases()) {
     os << "{" << alias.Serialize() << ": " << canonical.Serialize() << "}, ";
   }
-  os << "}, manual_sets = {";
-  for (const auto& [site, entry] : sets.manual_sets()) {
-    os << "{" << site.Serialize() << ": " << entry << "}, ";
-  }
   os << "}, manual_config = {";
   sets.manual_config().ForEachCustomizationEntry(
       [&](const net::SchemefulSite& site,
diff --git a/net/first_party_sets/global_first_party_sets.h b/net/first_party_sets/global_first_party_sets.h
index d77ce4d..9b867ef 100644
--- a/net/first_party_sets/global_first_party_sets.h
+++ b/net/first_party_sets/global_first_party_sets.h
@@ -91,6 +91,17 @@
   void ApplyManuallySpecifiedSet(
       const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries);
 
+  // Directly sets this instance's manual config. This is unsafe, because it
+  // assumes that the config was computed by this instance (or one with
+  // identical data), but cannot enforce that as a precondition.
+  //
+  // This must be public since at least one caller is above the //net layer, so
+  // we can't refer to the caller's type here (and therefore can't "friend" it
+  // and also can't use a base::Passkey).
+  //
+  // Must not be called if the manual config has already been set.
+  void UnsafeSetManualConfig(FirstPartySetsContextConfig manual_config);
+
   // Synchronously iterate over all entries in the public sets (i.e. not
   // including any manual set entries). Returns early if any of the iterations
   // returns false. Returns false if iteration was incomplete; true if all
@@ -100,6 +111,15 @@
       base::FunctionRef<bool(const SchemefulSite&, const FirstPartySetEntry&)>
           f) const;
 
+  // Synchronously iterate over the manual config. Returns early if any of the
+  // iterations returns false. Returns false if iteration was incomplete; true
+  // if all iterations returned true. No guarantees are made re: iteration
+  // order.
+  bool ForEachManualConfigEntry(
+      base::FunctionRef<bool(const SchemefulSite&,
+                             const absl::optional<FirstPartySetEntry>&)> f)
+      const;
+
   // Synchronously iterate over all the effective entries (i.e. anything that
   // could be returned by `FindEntry` using this instance and `config`,
   // including the manual set, policy sets, and aliases). Returns early if any
@@ -118,10 +138,6 @@
     return public_sets_version_;
   }
 
-  const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_sets() const {
-    return manual_sets_;
-  }
-
  private:
   // mojo (de)serialization needs access to private details.
   friend struct mojo::StructTraits<network::mojom::GlobalFirstPartySetsDataView,
@@ -134,7 +150,6 @@
       base::Version public_sets_version,
       base::flat_map<SchemefulSite, FirstPartySetEntry> entries,
       base::flat_map<SchemefulSite, SchemefulSite> aliases,
-      base::flat_map<SchemefulSite, FirstPartySetEntry> manual_sets,
       FirstPartySetsContextConfig manual_config);
 
   // Same as the public version of FindEntry, but is allowed to omit the
@@ -194,10 +209,6 @@
   // canonical representative, before looking it up in `entries_`.
   base::flat_map<SchemefulSite, SchemefulSite> aliases_;
 
-  // A map representing the manually-specified sets. Contains entries for
-  // aliases as well as canonical sites.
-  base::flat_map<SchemefulSite, FirstPartySetEntry> manual_sets_;
-
   // Stores the customizations induced by the manually-specified set. May be
   // empty if no switch was provided.
   FirstPartySetsContextConfig manual_config_;
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 6d49aa3..d882fcb 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -170,6 +170,8 @@
     ":maybe_set_appcontainer_acls",
     "//base:base_static",
   ]
+
+  libs = [ "userenv.lib" ]
 }
 
 test("sbox_integration_tests") {
diff --git a/sandbox/win/src/app_container_base.cc b/sandbox/win/src/app_container_base.cc
index 4eddb32..2840f1a7 100644
--- a/sandbox/win/src/app_container_base.cc
+++ b/sandbox/win/src/app_container_base.cc
@@ -25,18 +25,6 @@
 
 namespace {
 
-typedef decltype(::CreateAppContainerProfile) CreateAppContainerProfileFunc;
-
-typedef decltype(::DeriveAppContainerSidFromAppContainerName)
-    DeriveAppContainerSidFromAppContainerNameFunc;
-
-typedef decltype(::DeleteAppContainerProfile) DeleteAppContainerProfileFunc;
-
-typedef decltype(::GetAppContainerFolderPath) GetAppContainerFolderPathFunc;
-
-typedef decltype(
-    ::GetAppContainerRegistryLocation) GetAppContainerRegistryLocationFunc;
-
 struct FreeSidDeleter {
   inline void operator()(void* ptr) const { ::FreeSid(ptr); }
 };
@@ -82,14 +70,8 @@
 AppContainerBase* AppContainerBase::CreateProfile(const wchar_t* package_name,
                                                   const wchar_t* display_name,
                                                   const wchar_t* description) {
-  static auto create_app_container_profile =
-      reinterpret_cast<CreateAppContainerProfileFunc*>(GetProcAddress(
-          GetModuleHandle(L"userenv"), "CreateAppContainerProfile"));
-  if (!create_app_container_profile)
-    return nullptr;
-
   PSID package_sid_ptr = nullptr;
-  HRESULT hr = create_app_container_profile(
+  HRESULT hr = ::CreateAppContainerProfile(
       package_name, display_name, description, nullptr, 0, &package_sid_ptr);
   if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
     return Open(package_name);
@@ -105,15 +87,9 @@
 
 // static
 AppContainerBase* AppContainerBase::Open(const wchar_t* package_name) {
-  static auto derive_app_container_sid =
-      reinterpret_cast<DeriveAppContainerSidFromAppContainerNameFunc*>(
-          GetProcAddress(GetModuleHandle(L"userenv"),
-                         "DeriveAppContainerSidFromAppContainerName"));
-  if (!derive_app_container_sid)
-    return nullptr;
-
   PSID package_sid_ptr = nullptr;
-  HRESULT hr = derive_app_container_sid(package_name, &package_sid_ptr);
+  HRESULT hr = ::DeriveAppContainerSidFromAppContainerName(package_name,
+                                                           &package_sid_ptr);
   if (FAILED(hr))
     return nullptr;
 
@@ -135,13 +111,7 @@
 
 // static
 bool AppContainerBase::Delete(const wchar_t* package_name) {
-  static auto delete_app_container_profile =
-      reinterpret_cast<DeleteAppContainerProfileFunc*>(GetProcAddress(
-          GetModuleHandle(L"userenv"), "DeleteAppContainerProfile"));
-  if (!delete_app_container_profile)
-    return false;
-
-  return SUCCEEDED(delete_app_container_profile(package_name));
+  return SUCCEEDED(::DeleteAppContainerProfile(package_name));
 }
 
 AppContainerBase::AppContainerBase(base::win::Sid& package_sid,
@@ -168,36 +138,24 @@
 
 bool AppContainerBase::GetRegistryLocation(REGSAM desired_access,
                                            base::win::ScopedHandle* key) {
-  static GetAppContainerRegistryLocationFunc*
-      get_app_container_registry_location =
-          reinterpret_cast<GetAppContainerRegistryLocationFunc*>(GetProcAddress(
-              GetModuleHandle(L"userenv"), "GetAppContainerRegistryLocation"));
-  if (!get_app_container_registry_location)
-    return false;
-
   base::win::ScopedHandle token;
   if (BuildLowBoxToken(&token) != SBOX_ALL_OK)
     return false;
 
   ScopedImpersonation impersonation(token);
   HKEY key_handle;
-  if (FAILED(get_app_container_registry_location(desired_access, &key_handle)))
+  if (FAILED(::GetAppContainerRegistryLocation(desired_access, &key_handle)))
     return false;
   key->Set(key_handle);
   return true;
 }
 
 bool AppContainerBase::GetFolderPath(base::FilePath* file_path) {
-  static GetAppContainerFolderPathFunc* get_app_container_folder_path =
-      reinterpret_cast<GetAppContainerFolderPathFunc*>(GetProcAddress(
-          GetModuleHandle(L"userenv"), "GetAppContainerFolderPath"));
-  if (!get_app_container_folder_path)
-    return false;
   auto sddl_str = package_sid_.ToSddlString();
   if (!sddl_str)
     return false;
   base::win::ScopedCoMem<wchar_t> path_str;
-  if (FAILED(get_app_container_folder_path(sddl_str->c_str(), &path_str)))
+  if (FAILED(::GetAppContainerFolderPath(sddl_str->c_str(), &path_str)))
     return false;
   *file_path = base::FilePath(path_str.get());
   return true;
diff --git a/sandbox/win/src/lpc_policy_test.cc b/sandbox/win/src/lpc_policy_test.cc
index e11c3c3e..2c21632 100644
--- a/sandbox/win/src/lpc_policy_test.cc
+++ b/sandbox/win/src/lpc_policy_test.cc
@@ -97,35 +97,13 @@
   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd.c_str()));
 }
 
-// GetUserDefaultLocaleName is not available on WIN XP.  So we'll
-// load it on-the-fly.
-const wchar_t kKernel32DllName[] = L"kernel32.dll";
-typedef int(WINAPI* GetUserDefaultLocaleNameFunction)(LPWSTR lpLocaleName,
-                                                      int cchLocaleName);
-
 SBOX_TESTS_COMMAND int Lpc_GetUserDefaultLocaleName(int argc, wchar_t** argv) {
   if (argc != 1)
     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   std::wstring expected_locale_name(argv[0]);
-  static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func =
-      nullptr;
-  if (!GetUserDefaultLocaleName_func) {
-    // GetUserDefaultLocaleName is not available on WIN XP.  So we'll
-    // load it on-the-fly.
-    HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName);
-    if (!kernel32_dll) {
-      return SBOX_TEST_FAILED;
-    }
-    GetUserDefaultLocaleName_func =
-        reinterpret_cast<GetUserDefaultLocaleNameFunction>(
-            GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName"));
-    if (!GetUserDefaultLocaleName_func) {
-      return SBOX_TEST_FAILED;
-    }
-  }
   wchar_t locale_name[LOCALE_NAME_MAX_LENGTH] = {0};
   // This will cause an exception if not warmed up suitably.
-  int ret = GetUserDefaultLocaleName_func(
+  int ret = ::GetUserDefaultLocaleName(
       locale_name, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t));
   if (!ret) {
     return SBOX_TEST_FAILED;
@@ -141,20 +119,8 @@
 }
 
 TEST(LpcPolicyTest, GetUserDefaultLocaleName) {
-  static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func =
-      nullptr;
-  if (!GetUserDefaultLocaleName_func) {
-    // GetUserDefaultLocaleName is not available on WIN XP.  So we'll
-    // load it on-the-fly.
-    HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName);
-    EXPECT_NE(nullptr, kernel32_dll);
-    GetUserDefaultLocaleName_func =
-        reinterpret_cast<GetUserDefaultLocaleNameFunction>(
-            GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName"));
-    EXPECT_NE(nullptr, GetUserDefaultLocaleName_func);
-  }
   wchar_t locale_name[LOCALE_NAME_MAX_LENGTH] = {0};
-  EXPECT_NE(0, GetUserDefaultLocaleName_func(
+  EXPECT_NE(0, ::GetUserDefaultLocaleName(
                    locale_name, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t)));
   EXPECT_NE(0U, wcsnlen(locale_name, LOCALE_NAME_MAX_LENGTH));
   std::wstring cmd =
diff --git a/sandbox/win/src/process_mitigations_unittest.cc b/sandbox/win/src/process_mitigations_unittest.cc
index b5609f5..219aa9b8 100644
--- a/sandbox/win/src/process_mitigations_unittest.cc
+++ b/sandbox/win/src/process_mitigations_unittest.cc
@@ -35,22 +35,6 @@
 namespace {
 
 //------------------------------------------------------------------------------
-// Internal Defines & Functions
-//------------------------------------------------------------------------------
-
-// API defined in winbase.h.
-using GetProcessDEPPolicyFunction = decltype(&GetProcessDEPPolicy);
-
-// API defined in processthreadsapi.h.
-using GetProcessMitigationPolicyFunction =
-    decltype(&GetProcessMitigationPolicy);
-GetProcessMitigationPolicyFunction get_process_mitigation_policy;
-
-// APIs defined in wingdi.h.
-using AddFontMemResourceExFunction = decltype(&AddFontMemResourceEx);
-using RemoveFontMemResourceExFunction = decltype(&RemoveFontMemResourceEx);
-
-//------------------------------------------------------------------------------
 // NonSystemFont test helper function.
 //
 // 1. Pick font file and set up sandbox to allow read access to it.
@@ -173,12 +157,6 @@
   if (!test)
     return SBOX_TEST_INVALID_PARAMETER;
 
-  get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
-  if (!get_process_mitigation_policy)
-    return SBOX_TEST_NOT_FOUND;
-
   switch (test) {
     //--------------------------------------------------
     // MITIGATION_DEP
@@ -188,9 +166,8 @@
 #if !defined(_WIN64)
       // DEP - always enabled on 64-bit.
       PROCESS_MITIGATION_DEP_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessDEPPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), ProcessDEPPolicy,
+                                        &policy, sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.Enable || !policy.Permanent)
@@ -204,9 +181,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_ASLR): {
       PROCESS_MITIGATION_ASLR_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessASLRPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessASLRPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.EnableForceRelocateImages || !policy.DisallowStrippedImages)
@@ -219,9 +196,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_STRICTHANDLE): {
       PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessStrictHandleCheckPolicy,
-                                         &policy, sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessStrictHandleCheckPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.RaiseExceptionOnInvalidHandleReference ||
@@ -236,9 +213,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_WIN32K): {
       PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessSystemCallDisablePolicy,
-                                         &policy, sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessSystemCallDisablePolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.DisallowWin32kSystemCalls)
@@ -255,9 +232,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_EXTENSIONPOINT): {
       PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessExtensionPointDisablePolicy,
-                                         &policy, sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessExtensionPointDisablePolicy,
+                                        &policy, sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.DisableExtensionPoints)
@@ -270,9 +247,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_DYNAMICCODE): {
       PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessDynamicCodePolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessDynamicCodePolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.ProhibitDynamicCode)
@@ -285,9 +262,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_NONSYSFONT): {
       PROCESS_MITIGATION_FONT_DISABLE_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessFontDisablePolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessFontDisablePolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.DisableNonSystemFonts)
@@ -300,9 +277,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_MSSIGNED): {
       PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessSignaturePolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessSignaturePolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.MicrosoftSignedOnly)
@@ -315,9 +292,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_LOADNOREMOTE): {
       PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessImageLoadPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessImageLoadPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.NoRemoteImages)
@@ -330,9 +307,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_LOADNOLOW): {
       PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessImageLoadPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessImageLoadPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.NoLowMandatoryLabelImages)
@@ -345,9 +322,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_DYNAMICCODEOPTOUT): {
       PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessDynamicCodePolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessDynamicCodePolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.ProhibitDynamicCode || !policy.AllowThreadOptOut)
@@ -360,9 +337,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_LOADPREFERSYS32): {
       PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessImageLoadPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessImageLoadPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.PreferSystem32Images)
@@ -385,9 +362,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_CETDISABLED): {
       PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessUserShadowStackPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessUserShadowStackPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       // We wish to disable the policy.
@@ -401,9 +378,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_CETDYNAMICAPIS): {
       PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessUserShadowStackPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessUserShadowStackPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
 
@@ -424,9 +401,9 @@
     //--------------------------------------------------
     case (TESTPOLICY_CETSTRICT): {
       PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessUserShadowStackPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessUserShadowStackPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
 
@@ -464,9 +441,9 @@
     case (TESTPOLICY_PREANDPOSTSTARTUP): {
       // Both policies should be set now.
       PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
-      if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                         ProcessImageLoadPolicy, &policy,
-                                         sizeof(policy))) {
+      if (!::GetProcessMitigationPolicy(::GetCurrentProcess(),
+                                        ProcessImageLoadPolicy, &policy,
+                                        sizeof(policy))) {
         return SBOX_TEST_NOT_FOUND;
       }
       if (!policy.NoLowMandatoryLabelImages)
@@ -485,44 +462,6 @@
   return SBOX_TEST_SUCCEEDED;
 }
 
-SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t** argv) {
-  GetProcessDEPPolicyFunction get_process_dep_policy =
-      reinterpret_cast<GetProcessDEPPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessDEPPolicy"));
-  if (get_process_dep_policy) {
-    BOOL is_permanent = false;
-    DWORD dep_flags = 0;
-
-    if (!get_process_dep_policy(::GetCurrentProcess(), &dep_flags,
-                                &is_permanent)) {
-      return SBOX_TEST_FIRST_ERROR;
-    }
-
-    if (!(dep_flags & PROCESS_DEP_ENABLE) || !is_permanent)
-      return SBOX_TEST_SECOND_ERROR;
-
-  } else {
-    ULONG size = 0;
-    ULONG dep_flags = 0;
-    if (!SUCCEEDED(GetNtExports()->QueryInformationProcess(
-            ::GetCurrentProcess(), ProcessExecuteFlags, &dep_flags,
-            sizeof(dep_flags), &size))) {
-      return SBOX_TEST_THIRD_ERROR;
-    }
-
-    static const int MEM_EXECUTE_OPTION_DISABLE = 2;
-    static const int MEM_EXECUTE_OPTION_PERMANENT = 8;
-    dep_flags &= 0xff;
-
-    if (dep_flags !=
-        (MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT)) {
-      return SBOX_TEST_FOURTH_ERROR;
-    }
-  }
-
-  return SBOX_TEST_SUCCEEDED;
-}
-
 // ForceMsSigned tests:
 // Try to load the DLL given in arg1.
 SBOX_TESTS_COMMAND int TestDllLoad(int argc, wchar_t** argv) {
@@ -541,30 +480,11 @@
 
 // This test attempts a non-system font load.
 //
-// 1) Load gdi32.dll for required font APIs.
-// 2) Load file contents of font file passed in arg1 into memory.
-// 3) Call API to try loading a non-system font.
-//
 // Arg1: Full path to font file to try loading.
 SBOX_TESTS_COMMAND int CheckWin10FontLoad(int argc, wchar_t** argv) {
   if (argc < 1)
     return SBOX_TEST_INVALID_PARAMETER;
 
-  HMODULE gdi_module = ::LoadLibraryW(L"gdi32.dll");
-  if (!gdi_module)
-    return SBOX_TEST_NOT_FOUND;
-
-  AddFontMemResourceExFunction add_font_mem_resource =
-      reinterpret_cast<AddFontMemResourceExFunction>(
-          ::GetProcAddress(gdi_module, "AddFontMemResourceEx"));
-
-  RemoveFontMemResourceExFunction rem_font_mem_resource =
-      reinterpret_cast<RemoveFontMemResourceExFunction>(
-          ::GetProcAddress(gdi_module, "RemoveFontMemResourceEx"));
-
-  if (!add_font_mem_resource || !rem_font_mem_resource)
-    return SBOX_TEST_NOT_FOUND;
-
   // Open font file passed in as an argument.
   base::File file(base::FilePath(argv[0]),
                   base::File::FLAG_OPEN | base::File::FLAG_READ);
@@ -585,12 +505,12 @@
     return SBOX_TEST_NOT_FOUND;
 
   DWORD font_count = 0;
-  HANDLE font_handle =
-      add_font_mem_resource(&font_data[0], static_cast<DWORD>(font_data.size()),
-                            nullptr, &font_count);
+  HANDLE font_handle = ::AddFontMemResourceEx(
+      &font_data[0], static_cast<DWORD>(font_data.size()), nullptr,
+      &font_count);
 
   if (font_handle) {
-    rem_font_mem_resource(font_handle);
+    ::RemoveFontMemResourceEx(font_handle);
     return SBOX_TEST_SUCCEEDED;
   }
 
@@ -668,6 +588,14 @@
 // This test validates that setting the MITIGATION_DEP*
 // mitigations enables the setting on a process.
 TEST(ProcessMitigationsTest, CheckDepWin8PolicySuccess) {
+  DWORD flags;
+  BOOL permanent;
+  ASSERT_TRUE(::GetProcessDEPPolicy(::GetCurrentProcess(), &flags, &permanent));
+  // If DEP is enabled permanently these tests are meaningless. Just ignore them
+  // for this system.
+  if (permanent)
+    return;
+
   std::wstring test_command = L"CheckPolicy ";
   test_command += std::to_wstring(TESTPOLICY_DEP);
 
@@ -1136,14 +1064,10 @@
 
   // Verify policy is available and set for this process (i.e. CET is
   // enabled via IFEO or through the CETCOMPAT bit on the executable).
-  auto get_process_mitigation_policy =
-      reinterpret_cast<decltype(&GetProcessMitigationPolicy)>(::GetProcAddress(
-          ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy"));
-
   PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY uss_policy;
-  if (!get_process_mitigation_policy(GetCurrentProcess(),
-                                     ProcessUserShadowStackPolicy, &uss_policy,
-                                     sizeof(uss_policy))) {
+  if (!::GetProcessMitigationPolicy(GetCurrentProcess(),
+                                    ProcessUserShadowStackPolicy, &uss_policy,
+                                    sizeof(uss_policy))) {
     return;
   }
 
@@ -1180,14 +1104,10 @@
 
   // Verify policy is available and set for this process (i.e. CET is
   // enabled via IFEO or through the CETCOMPAT bit on the executable).
-  auto get_process_mitigation_policy =
-      reinterpret_cast<decltype(&GetProcessMitigationPolicy)>(::GetProcAddress(
-          ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy"));
-
   PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY uss_policy;
-  if (!get_process_mitigation_policy(GetCurrentProcess(),
-                                     ProcessUserShadowStackPolicy, &uss_policy,
-                                     sizeof(uss_policy))) {
+  if (!::GetProcessMitigationPolicy(GetCurrentProcess(),
+                                    ProcessUserShadowStackPolicy, &uss_policy,
+                                    sizeof(uss_policy))) {
     return;
   }
 
@@ -1222,14 +1142,10 @@
 
   // Verify policy is available and set for this process (i.e. CET is
   // enabled via IFEO or through the CETCOMPAT bit on the executable).
-  auto get_process_mitigation_policy =
-      reinterpret_cast<decltype(&GetProcessMitigationPolicy)>(::GetProcAddress(
-          ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy"));
-
   PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY uss_policy;
-  if (!get_process_mitigation_policy(GetCurrentProcess(),
-                                     ProcessUserShadowStackPolicy, &uss_policy,
-                                     sizeof(uss_policy))) {
+  if (!::GetProcessMitigationPolicy(GetCurrentProcess(),
+                                    ProcessUserShadowStackPolicy, &uss_policy,
+                                    sizeof(uss_policy))) {
     return;
   }
 
diff --git a/services/device/public/cpp/bluetooth/OWNERS b/services/device/public/cpp/bluetooth/OWNERS
index d101120..66dd0fb 100644
--- a/services/device/public/cpp/bluetooth/OWNERS
+++ b/services/device/public/cpp/bluetooth/OWNERS
@@ -1,4 +1,4 @@
-file://services/device/bluetooth/OWNERS
+file://device/bluetooth/OWNERS
 
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/services/network/p2p/socket.cc b/services/network/p2p/socket.cc
index e196189..9c7db1f 100644
--- a/services/network/p2p/socket.cc
+++ b/services/network/p2p/socket.cc
@@ -74,26 +74,7 @@
       base::BindOnce(&P2PSocket::OnError, base::Unretained(this)));
 }
 
-P2PSocket::~P2PSocket() {
-  if (protocol_type_ == P2PSocket::UDP) {
-    UMA_HISTOGRAM_COUNTS_10000("WebRTC.SystemMaxConsecutiveBytesDelayed_UDP",
-                               send_bytes_delayed_max_);
-  } else {
-    UMA_HISTOGRAM_COUNTS_10000("WebRTC.SystemMaxConsecutiveBytesDelayed_TCP",
-                               send_bytes_delayed_max_);
-  }
-
-  if (send_packets_total_ > 0) {
-    int delay_rate = (send_packets_delayed_total_ * 100) / send_packets_total_;
-    if (protocol_type_ == P2PSocket::UDP) {
-      UMA_HISTOGRAM_PERCENTAGE("WebRTC.SystemPercentPacketsDelayed_UDP",
-                               delay_rate);
-    } else {
-      UMA_HISTOGRAM_PERCENTAGE("WebRTC.SystemPercentPacketsDelayed_TCP",
-                               delay_rate);
-    }
-  }
-}
+P2PSocket::~P2PSocket() = default;
 
 // Verifies that the packet |data| has a valid STUN header.
 // static
@@ -195,26 +176,6 @@
   return receiver_.Unbind();
 }
 
-void P2PSocket::IncrementDelayedPackets() {
-  send_packets_delayed_total_++;
-}
-
-void P2PSocket::IncrementTotalSentPackets() {
-  send_packets_total_++;
-}
-
-void P2PSocket::IncrementDelayedBytes(uint32_t size) {
-  send_bytes_delayed_cur_ += size;
-  if (send_bytes_delayed_cur_ > send_bytes_delayed_max_) {
-    send_bytes_delayed_max_ = send_bytes_delayed_cur_;
-  }
-}
-
-void P2PSocket::DecrementDelayedBytes(uint32_t size) {
-  send_bytes_delayed_cur_ -= size;
-  DCHECK_GE(send_bytes_delayed_cur_, 0);
-}
-
 void P2PSocket::OnError() {
   receiver_.reset();
   client_.reset();
diff --git a/services/network/p2p/socket.h b/services/network/p2p/socket.h
index b74221d..34114231 100644
--- a/services/network/p2p/socket.h
+++ b/services/network/p2p/socket.h
@@ -150,12 +150,6 @@
   // destroy the socket.
   void OnError();
 
-  // Used by subclasses to track the metrics of delayed bytes and packets.
-  void IncrementDelayedPackets();
-  void IncrementTotalSentPackets();
-  void IncrementDelayedBytes(uint32_t size);
-  void DecrementDelayedBytes(uint32_t size);
-
   raw_ptr<Delegate> delegate_;
   mojo::Remote<mojom::P2PSocketClient> client_;
   mojo::Receiver<mojom::P2PSocket> receiver_;
@@ -163,16 +157,6 @@
   ProtocolType protocol_type_;
 
  private:
-  // Track total delayed packets for calculating how many packets are
-  // delayed by system at the end of call.
-  uint32_t send_packets_delayed_total_ = 0;
-  uint32_t send_packets_total_ = 0;
-
-  // Track the maximum of consecutive delayed bytes caused by system's
-  // EWOULDBLOCK.
-  int32_t send_bytes_delayed_max_ = 0;
-  int32_t send_bytes_delayed_cur_ = 0;
-
   base::WeakPtrFactory<P2PSocket> weak_ptr_factory_{this};
 };
 
diff --git a/services/network/p2p/socket_tcp.cc b/services/network/p2p/socket_tcp.cc
index cdbb286..5970b6f1 100644
--- a/services/network/p2p/socket_tcp.cc
+++ b/services/network/p2p/socket_tcp.cc
@@ -253,11 +253,8 @@
 }
 
 void P2PSocketTcpBase::WriteOrQueue(SendBuffer& send_buffer) {
-  IncrementTotalSentPackets();
   if (write_buffer_.buffer.get()) {
     write_queue_.push(send_buffer);
-    IncrementDelayedPackets();
-    IncrementDelayedBytes(send_buffer.buffer->size());
     return;
   }
 
@@ -312,8 +309,6 @@
     } else {
       write_buffer_ = write_queue_.front();
       write_queue_.pop();
-      // Update how many bytes are still waiting to be sent.
-      DecrementDelayedBytes(write_buffer_.buffer->size());
     }
   }
   return true;
diff --git a/services/network/p2p/socket_udp.cc b/services/network/p2p/socket_udp.cc
index a0503e6..800c303 100644
--- a/services/network/p2p/socket_udp.cc
+++ b/services/network/p2p/socket_udp.cc
@@ -351,7 +351,6 @@
     send_queue_.pop_front();
     if (!DoSend(packet))
       return;
-    DecrementDelayedBytes(packet.size);
   }
 }
 
@@ -395,15 +394,11 @@
     return;
   }
 
-  IncrementTotalSentPackets();
-
   if (send_pending_) {
     send_queue_.push_back(
         PendingPacket(packet_info.destination, data, packet_info.packet_options,
                       packet_info.packet_id,
                       net::NetworkTrafficAnnotationTag(traffic_annotation)));
-    IncrementDelayedBytes(data.size());
-    IncrementDelayedPackets();
   } else {
     PendingPacket packet(packet_info.destination, data,
                          packet_info.packet_options, packet_info.packet_id,
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.cc b/services/network/public/cpp/first_party_sets_mojom_traits.cc
index 933c281..d07fa34 100644
--- a/services/network/public/cpp/first_party_sets_mojom_traits.cc
+++ b/services/network/public/cpp/first_party_sets_mojom_traits.cc
@@ -162,17 +162,12 @@
   if (!sets.ReadAliases(&aliases))
     return false;
 
-  base::flat_map<net::SchemefulSite, net::FirstPartySetEntry> manual_entries;
-  if (!sets.ReadManualEntries(&manual_entries))
-    return false;
-
   net::FirstPartySetsContextConfig manual_config;
   if (!sets.ReadManualConfig(&manual_config))
     return false;
 
-  *out_sets = net::GlobalFirstPartySets(
-      std::move(public_sets_version), std::move(entries), std::move(aliases),
-      std::move(manual_entries), std::move(manual_config));
+  *out_sets = net::GlobalFirstPartySets(std::move(public_sets_version), entries,
+                                        aliases, std::move(manual_config));
 
   return true;
 }
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.h b/services/network/public/cpp/first_party_sets_mojom_traits.h
index 3368479..fd56019 100644
--- a/services/network/public/cpp/first_party_sets_mojom_traits.h
+++ b/services/network/public/cpp/first_party_sets_mojom_traits.h
@@ -126,11 +126,6 @@
     return sets.aliases();
   }
 
-  static const base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>&
-  manual_entries(const net::GlobalFirstPartySets& sets) {
-    return sets.manual_sets();
-  }
-
   static const net::FirstPartySetsContextConfig& manual_config(
       const net::GlobalFirstPartySets& sets) {
     return sets.manual_config();
diff --git a/services/network/public/mojom/first_party_sets.mojom b/services/network/public/mojom/first_party_sets.mojom
index b733608..a7b8beb 100644
--- a/services/network/public/mojom/first_party_sets.mojom
+++ b/services/network/public/mojom/first_party_sets.mojom
@@ -91,10 +91,6 @@
   // The mapping from site alias to canonical site from public sets.
   map<SchemefulSite, SchemefulSite> aliases;
 
-  // The mapping of site to FPS entry representing the parsed manually-supplied
-  // set, without taking the underlying public sets into account.
-  map<SchemefulSite, FirstPartySetEntry> manual_entries;
-
   // The config induced by the manually-supplied set.
   FirstPartySetsContextConfig manual_config;
 };
diff --git a/storage/browser/quota/quota_manager_impl.cc b/storage/browser/quota/quota_manager_impl.cc
index f0ac51fa..194692a 100644
--- a/storage/browser/quota/quota_manager_impl.cc
+++ b/storage/browser/quota/quota_manager_impl.cc
@@ -2610,8 +2610,10 @@
     const QuotaSettings& settings) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  int64_t temporary_usage =
-      GetUsageTracker(StorageType::kTemporary)->GetCachedUsage();
+  auto* temporary_usage_tracker = GetUsageTracker(StorageType::kTemporary);
+  int64_t temporary_usage = temporary_usage_tracker == nullptr
+                                ? 0
+                                : temporary_usage_tracker->GetCachedUsage();
   DCHECK_GE(temporary_usage, -1);
 
   int64_t available_space =
diff --git a/storage/browser/quota/quota_manager_unittest.cc b/storage/browser/quota/quota_manager_unittest.cc
index c9fe371..275d6c0 100644
--- a/storage/browser/quota/quota_manager_unittest.cc
+++ b/storage/browser/quota/quota_manager_unittest.cc
@@ -2775,20 +2775,35 @@
 }
 
 TEST_F(QuotaManagerImplTest, GetDiskAvailabilityAndTempPoolSize) {
-  const int kPoolSize = 1000;
-  const int kPerHostQuota = kPoolSize / 5;
-  SetQuotaSettings(kPoolSize, kPerHostQuota, 0);
-  storage::StorageCapacityResult storage_capacity = GetStorageCapacity();
+  ResetQuotaManagerImpl(/*is_incognito=*/false);
 
   base::test::TestFuture<int64_t, int64_t, int64_t> quota_internals_future;
   quota_manager_impl()->GetDiskAvailabilityAndTempPoolSize(
       quota_internals_future.GetCallback());
   std::tuple quota_internals_result = quota_internals_future.Take();
 
-  EXPECT_EQ(storage_capacity.total_space, std::get<0>(quota_internals_result));
-  EXPECT_EQ(storage_capacity.available_space,
-            std::get<1>(quota_internals_result));
-  EXPECT_EQ(kPoolSize, std::get<2>(quota_internals_result));
+  int64_t available_space =
+      static_cast<uint64_t>(GetAvailableDiskSpaceForTest());
+  int64_t total_space = available_space * 2;
+
+  EXPECT_EQ(total_space, std::get<0>(quota_internals_result));
+  EXPECT_EQ(available_space, std::get<1>(quota_internals_result));
+  EXPECT_EQ(kDefaultPoolSize, std::get<2>(quota_internals_result));
+}
+
+TEST_F(QuotaManagerImplTest, GetDiskAvailabilityAndTempPoolSize_Incognito) {
+  // Test to make sure total_space and available_space are retrieved
+  // as expected, without producing a crash.
+  ResetQuotaManagerImpl(/*is_incognito=*/true);
+
+  base::test::TestFuture<int64_t, int64_t, int64_t> quota_internals_future;
+  quota_manager_impl()->GetDiskAvailabilityAndTempPoolSize(
+      quota_internals_future.GetCallback());
+  std::tuple quota_internals_result = quota_internals_future.Take();
+
+  EXPECT_EQ(kDefaultPoolSize, std::get<0>(quota_internals_result));
+  EXPECT_EQ(kDefaultPoolSize, std::get<1>(quota_internals_result));
+  EXPECT_EQ(kDefaultPoolSize, std::get<2>(quota_internals_result));
 }
 
 TEST_F(QuotaManagerImplTest, NotifyAndLRUBucket) {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 4d754c28..1158e37 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5923,9 +5923,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -5937,8 +5937,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -6090,9 +6090,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6104,8 +6104,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -6242,9 +6242,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6256,8 +6256,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0df54b2..3b087f9 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -87397,9 +87397,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -87411,8 +87411,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -87534,9 +87534,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -87548,8 +87548,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -87661,9 +87661,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -87675,8 +87675,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -89017,9 +89017,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -89030,8 +89030,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -89184,9 +89184,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -89197,8 +89197,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -89336,9 +89336,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -89349,8 +89349,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -90872,9 +90872,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -90885,8 +90885,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -91039,9 +91039,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -91052,8 +91052,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -91191,9 +91191,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -91204,8 +91204,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -91973,9 +91973,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -91986,8 +91986,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index a4196bf..5792ac3 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -18604,11 +18604,11 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18620,8 +18620,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -18785,11 +18785,11 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18801,8 +18801,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
@@ -18947,11 +18947,11 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots"
         ],
-        "description": "Run with ash-chrome version 110.0.5433.0",
+        "description": "Run with ash-chrome version 110.0.5434.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18963,8 +18963,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5433.0",
-              "revision": "version:110.0.5433.0"
+              "location": "lacros_version_skew_tests_v110.0.5434.0",
+              "revision": "version:110.0.5434.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter
index e031f492..7b327d8 100644
--- a/testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter
@@ -118,6 +118,7 @@
 -org.chromium.chrome.browser.autofill_assistant.AutofillAssistantAutostartTest*
 -org.chromium.chrome.browser.autofill_assistant.AutofillAssistantPasswordManagerIntegrationTest*
 
-
+# crbug.com/1392774
+-org.chromium.chrome.browser.display_cutout.DisplayCutoutTest.testViewportFitCover
 
 
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 2a16ac277..52f973c 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5433.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5434.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 110.0.5433.0',
+    'description': 'Run with ash-chrome version 110.0.5434.0',
     'identifier': 'Lacros version skew testing ash canary',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v110.0.5433.0',
-          'revision': 'version:110.0.5433.0',
+          'location': 'lacros_version_skew_tests_v110.0.5434.0',
+          'revision': 'version:110.0.5434.0',
         },
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 06be3c47..bf834a6 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -7844,10 +7844,13 @@
             ]
         }
     ],
-    "PageInfoAboutThisSiteMoreInfo": [
+    "PageInfoAboutThisSiteMoreInfoDesktop": [
         {
             "platforms": [
-                "android"
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
             ],
             "experiments": [
                 {
@@ -8208,11 +8211,7 @@
         {
             "platforms": [
                 "chromeos",
-                "chromeos_lacros",
-                "fuchsia",
-                "linux",
-                "mac",
-                "windows"
+                "chromeos_lacros"
             ],
             "experiments": [
                 {
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 4fb00f80..c9d75e6 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -922,13 +922,6 @@
              "SanitizerAPINamespacesForTesting",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Kill switch for the blocking of the navigation of top from a cross origin
-// iframe to a different protocol. TODO(https://crbug.com/1151507): Remove in
-// M92.
-BASE_FEATURE(kBlockCrossOriginTopNavigationToDiffentScheme,
-             "BlockCrossOriginTopNavigationToDiffentScheme",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Kill switch for the Interest Group API, i.e. if disabled, the
 // API exposure will be disabled regardless of the OT config.
 BASE_FEATURE(kInterestGroupStorage,
diff --git a/third_party/blink/common/widget/visual_properties_mojom_traits.cc b/third_party/blink/common/widget/visual_properties_mojom_traits.cc
index 9e84b3f..4bb2ef7 100644
--- a/third_party/blink/common/widget/visual_properties_mojom_traits.cc
+++ b/third_party/blink/common/widget/visual_properties_mojom_traits.cc
@@ -36,6 +36,8 @@
   out->page_scale_factor = data.page_scale_factor();
   out->compositing_scale_factor = data.compositing_scale_factor();
   out->is_pinch_gesture_active = data.is_pinch_gesture_active();
+  out->virtual_keyboard_resize_height_physical_px =
+      data.virtual_keyboard_resize_height_physical_px();
   return true;
 }
 
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 89f5a66..4a28dcf2 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -383,12 +383,6 @@
 
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSanitizerAPINamespaces);
 
-// Kill switch for the blocking of the navigation of top from a cross origin
-// iframe to a different scheme. TODO(https://crbug.com/1151507): Remove in
-// M92.
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
-    kBlockCrossOriginTopNavigationToDiffentScheme);
-
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kJXL);
 
 // Main controls for ad serving API features.
diff --git a/third_party/blink/public/common/widget/visual_properties.h b/third_party/blink/public/common/widget/visual_properties.h
index 00373f08..3976640 100644
--- a/third_party/blink/public/common/widget/visual_properties.h
+++ b/third_party/blink/public/common/widget/visual_properties.h
@@ -88,6 +88,11 @@
   // controls shrink blink size etc.
   cc::BrowserControlsParams browser_controls_params;
 
+  // If shown and resizing the renderer, returns the height of the virtual
+  // keyboard in physical pixels. Otherwise, returns 0. Always 0 in a
+  // non-outermost main frame.
+  int virtual_keyboard_resize_height_physical_px = 0;
+
   // Whether or not the focused node should be scrolled into view after the
   // resize.
   bool scroll_focused_node_into_view = false;
diff --git a/third_party/blink/public/common/widget/visual_properties_mojom_traits.h b/third_party/blink/public/common/widget/visual_properties_mojom_traits.h
index 4c788d2..0ee9e77 100644
--- a/third_party/blink/public/common/widget/visual_properties_mojom_traits.h
+++ b/third_party/blink/public/common/widget/visual_properties_mojom_traits.h
@@ -80,6 +80,11 @@
     return r.zoom_level;
   }
 
+  static int virtual_keyboard_resize_height_physical_px(
+      const blink::VisualProperties& r) {
+    return r.virtual_keyboard_resize_height_physical_px;
+  }
+
   static double page_scale_factor(const blink::VisualProperties& r) {
     DCHECK_GT(r.page_scale_factor, 0);
     return r.page_scale_factor;
diff --git a/third_party/blink/public/mojom/devtools/devtools_agent.mojom b/third_party/blink/public/mojom/devtools/devtools_agent.mojom
index 2d2fd85..fda68c3 100644
--- a/third_party/blink/public/mojom/devtools/devtools_agent.mojom
+++ b/third_party/blink/public/mojom/devtools/devtools_agent.mojom
@@ -35,7 +35,8 @@
 // navigation-related interface, since we should reattach sessions before
 // the navigation commits in the frame.
 //
-// This interface is implemented in renderer hosting entity under debug.
+// This interface is implemented in renderer hosting entity under debug,
+// and is used by the browser-side DevToolsSession and agent hosts.
 // Note that this interface just provides a mean to start a debugging session,
 // so the presence of it does not mean the entity is under debug just yet.
 interface DevToolsAgent {
@@ -90,13 +91,18 @@
   // session. The renderer must send this back with each response. The current
   // implementation uses the string serialization of an UnguessableToken, but
   // that is subject to change.
+  //
+  // |session_waits_for_debugger| indicates that the session has been created
+  // in the paused state and the agent should only resume execution when all
+  // such sessions have been resumed by the client.
   AttachDevToolsSession(pending_associated_remote<DevToolsSessionHost> host,
                         pending_associated_receiver<DevToolsSession> session,
                         pending_receiver<DevToolsSession> io_session,
                         DevToolsSessionState? reattach_session_state,
                         bool client_expects_binary_responses,
                         bool client_is_trusted,
-                        string session_id);
+                        string session_id,
+                        bool session_waits_for_debugger);
 
   // Requests an element at specific position to be inspected in every
   // attached session (or the next attached one if none yet).
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
index 3ddc537..fdac47b 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -3734,6 +3734,7 @@
   kDocumentLoaderDeliveryTypeNavigationalPrefetch = 4393,
   kSpeculationRulesHeader = 4394,
   kSpeculationRulesDocumentRules = 4395,
+  kFederatedCredentialManagementIframe = 4396,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/mojom/widget/visual_properties.mojom b/third_party/blink/public/mojom/widget/visual_properties.mojom
index b7e7b3b3..3c10634 100644
--- a/third_party/blink/public/mojom/widget/visual_properties.mojom
+++ b/third_party/blink/public/mojom/widget/visual_properties.mojom
@@ -100,4 +100,8 @@
   // frame.
   gfx.mojom.Rect window_controls_overlay_rect;
 
+  // If shown and resizing the renderer, returns the height of the virtual
+  // keyboard in physical pixels. Otherwise, returns 0. Always 0 in a
+  // non-outermost main frame.
+  uint32 virtual_keyboard_resize_height_physical_px;
 };
diff --git a/third_party/blink/renderer/build/scripts/make_runtime_feature_state_override_context.py b/third_party/blink/renderer/build/scripts/make_runtime_feature_state_override_context.py
index 991972d5..420ea7f 100755
--- a/third_party/blink/renderer/build/scripts/make_runtime_feature_state_override_context.py
+++ b/third_party/blink/renderer/build/scripts/make_runtime_feature_state_override_context.py
@@ -20,16 +20,15 @@
             (self.file_basename + '.cc'): self.generate_implementation,
             (self.file_basename + '.h'): self.generate_header,
         }
-        self._browser_read_access_features = util.browser_read_access(
-            self._features)
+        self._overridable_features = util.overridable_features(self._features)
 
     def _template_inputs(self):
         return {
             'features': self._features,
-            'browser_read_access_features': self._browser_read_access_features,
             'platforms': self._platforms(),
             'input_files': self._input_files,
             'header_guard': self._header_guard,
+            'overridable_features': self._overridable_features,
         }
 
     @template_expander.use_jinja(f'templates/{file_basename}.cc.tmpl')
diff --git a/third_party/blink/renderer/build/scripts/make_runtime_features.py b/third_party/blink/renderer/build/scripts/make_runtime_features.py
index bbca058..63c36442 100755
--- a/third_party/blink/renderer/build/scripts/make_runtime_features.py
+++ b/third_party/blink/renderer/build/scripts/make_runtime_features.py
@@ -123,6 +123,15 @@
 
         # Write features to file for bindings generation
         self._write_features_to_pickle_file(output_dir)
+        self._overridable_features = util.overridable_features(self._features)
+
+        overridable_set = set()
+        for feature in self._overridable_features:
+            overridable_set.add(str(feature['name']))
+
+        for feature in self._features:
+            feature['is_overridable_feature'] = str(
+                feature['name']) in overridable_set
 
     def _write_features_to_pickle_file(self, platform_output_dir):
         # TODO(yashard): Get the file path from args instead of hardcoding it.
diff --git a/third_party/blink/renderer/build/scripts/make_runtime_features_utilities.py b/third_party/blink/renderer/build/scripts/make_runtime_features_utilities.py
index 668d36b..ffd14b8 100644
--- a/third_party/blink/renderer/build/scripts/make_runtime_features_utilities.py
+++ b/third_party/blink/renderer/build/scripts/make_runtime_features_utilities.py
@@ -99,3 +99,21 @@
 
 def browser_write_access(features):
     return [f for f in features if f['browser_process_read_write_access']]
+
+
+def override_from_pref(features):
+    return [f for f in features if f['override_from_pref']]
+
+
+# The list of features we want to generate getters/setters for may contain
+# duplicates, so this function will return a deduped list.
+def overridable_features(features):
+    combined_list = override_from_pref(features) + browser_read_access(
+        features)
+    seen = set()
+    final_list = []
+    for f in combined_list:
+        if f['name'] not in seen:
+            seen.add(f['name'])
+            final_list.append(f)
+    return final_list
diff --git a/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
index fa90dc9..b5341f61 100644
--- a/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
@@ -112,9 +112,38 @@
   }
 }
 
+{% for feature in features %}
+{%if feature.is_overridable_feature and not feature.in_origin_trial%}
+bool RuntimeEnabledFeaturesBase::{{feature.name}}Enabled(const FeatureContext* context) {
+  if(context && context->GetRuntimeFeatureStateOverrideContext()
+                    ->Is{{feature.name}}ForceEnabled()) {
+    return true;
+  }
+  if(context && context->GetRuntimeFeatureStateOverrideContext()
+                    ->Is{{feature.name}}ForceDisabled()) {
+    return false;
+  }
+
+  return {{feature.name}}Enabled();
+}
+
+{% endif %}
+{% endfor %}
+
 {% for feature in origin_trial_controlled_features %}
 
 bool RuntimeEnabledFeaturesBase::{{feature.name}}Enabled(const FeatureContext* context) {
+  {% if feature.is_overridable_feature%}
+  if(context && context->GetRuntimeFeatureStateOverrideContext()
+                    ->Is{{feature.name}}ForceEnabled()) {
+    return true;
+  }
+  if(context && context->GetRuntimeFeatureStateOverrideContext()
+                    ->Is{{feature.name}}ForceDisabled()) {
+    return false;
+  }
+
+  {% endif %}
   {% for depends_on in feature.depends_on %}
   if (!RuntimeEnabledFeaturesBase::{{depends_on}}Enabled(context))
     return false;
diff --git a/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.h.tmpl b/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.h.tmpl
index d414c5d..78c83db 100644
--- a/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.h.tmpl
@@ -10,6 +10,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "third_party/blink/public/common/origin_trials/origin_trial_feature.h"
+#include "third_party/blink/renderer/platform/runtime_feature_state/runtime_feature_state_override_context.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
@@ -22,10 +23,13 @@
 namespace blink {
 
 // A pure virtual interface for checking the availability of origin trial
-// features in a context.
+// features in a context as well as whether a feature's state has been
+// overridden.
 class PLATFORM_EXPORT FeatureContext {
  public:
   virtual bool FeatureEnabled(OriginTrialFeature) const = 0;
+  virtual RuntimeFeatureStateOverrideContext*
+  GetRuntimeFeatureStateOverrideContext() const = 0;
 };
 
 // A class that stores static enablers for all experimental features.
@@ -57,7 +61,12 @@
     {% endfor %}
     return {{feature.data_member_name}};
   }
+
+  {% if feature.is_overridable_feature %}
+  static bool {{feature.name}}Enabled(const FeatureContext*);
+  {% else %}
   static bool {{feature.name}}Enabled(const FeatureContext*) { return {{feature.name}}Enabled(); }
+  {% endif %}
 
   {% endif %}
   {% endfor %}
diff --git a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.cc.tmpl
index 28b94de..779e6f6 100644
--- a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.cc.tmpl
@@ -3,31 +3,43 @@
 
 {{source_files_for_generated_file(template_file, input_files)}}
 
-#include "third_party/blink/renderer/core/runtime_feature_state/runtime_feature_state_override_context.h"
+#include "third_party/blink/renderer/platform/runtime_feature_state/runtime_feature_state_override_context.h"
 
 namespace blink {
-{% for feature in browser_read_access_features %}
+{% for feature in overridable_features %}
 bool RuntimeFeatureStateOverrideContext::
     Is{{feature.name}}ForceDisabled() {
-  // TODO(crbug.com/1377000): Get the real value.
-  return true;
+  auto it = override_values_.find(
+      OverridableFeatures::k{{feature.name}});
+  if (it != override_values_.end() && it->second == false)
+    return true;
+
+  return false;
 }
 
 bool RuntimeFeatureStateOverrideContext::
     Is{{feature.name}}ForceEnabled() {
-  // TODO(crbug.com/1377000): Get the real value.
-  return true;
+  auto it = override_values_.find(
+      OverridableFeatures::k{{feature.name}});
+  if(it != override_values_.end() && it->second == true)
+    return true;
+
+  return false;
 }
 
 void RuntimeFeatureStateOverrideContext::
     Set{{feature.name}}ForceDisabled() {
-  // TODO(crbug.com/1377000): Do something.
+  override_values_[OverridableFeatures::k{{feature.name}}] = false;
 }
 
 void RuntimeFeatureStateOverrideContext::
     Set{{feature.name}}ForceEnabled() {
-  // TODO(crbug.com/1377000): Do something.
+  override_values_[OverridableFeatures::k{{feature.name}}] = true;
 }
+
 {% endfor %}
+void RuntimeFeatureStateOverrideContext::ApplyEnterprisePolicyOverrides() {
+  // Get the enterprise policies here.
+}
 
 }  // namespace blink
\ No newline at end of file
diff --git a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.h.tmpl b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.h.tmpl
index 0bbe6c75..63da5d0c 100644
--- a/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/runtime_feature_state_override_context.h.tmpl
@@ -6,21 +6,24 @@
 #ifndef {{header_guard}}
 #define {{header_guard}}
 
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "base/containers/flat_map.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
 
 namespace blink {
 
 // This class coalesces browser side and enterprise policy state into a final
 // value which is then used to override the blink runtime feature state. It can
 // be queried with `Is*ForceEnabled()` or `Is*ForceDisabled()`.
-class RuntimeFeatureStateOverrideContext {
+class PLATFORM_EXPORT RuntimeFeatureStateOverrideContext
+    : public GarbageCollected<RuntimeFeatureStateOverrideContext> {
  public:
-  explicit RuntimeFeatureStateOverrideContext(
-      ExecutionContext* execution_context) {
-    // TODO(crbug.com/1377000): Actually init the object.
+  RuntimeFeatureStateOverrideContext() {
+    override_values_.reserve({{overridable_features|length()}});
+    ApplyEnterprisePolicyOverrides();
   }
 
-  {% for feature in browser_read_access_features %}
+  {% for feature in overridable_features %}
   bool Is{{feature.name}}ForceDisabled();
 
   bool Is{{feature.name}}ForceEnabled();
@@ -28,7 +31,21 @@
   void Set{{feature.name}}ForceDisabled();
 
   void Set{{feature.name}}ForceEnabled();
+
   {% endfor %}
+  void Trace(Visitor*) const {}
+
+ private:
+
+  enum class OverridableFeatures {
+    {% for feature in overridable_features %}
+    k{{feature.name}} = {{loop.index0}},
+    {% endfor %}
+  };
+
+  void ApplyEnterprisePolicyOverrides();
+
+  base::flat_map<OverridableFeatures, bool> override_values_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 011e28d6..2a958f9 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1136,28 +1136,6 @@
   deps = make_core_generated_deps
 }
 
-blink_python_runner(
-    "make_core_generated_runtime_feature_state_override_context") {
-  script = "../build/scripts/make_runtime_feature_state_override_context.py"
-
-  inputs = scripts_for_json5_files + [
-             "../build/scripts/make_runtime_feature_state_override_context.py",
-             "../platform/runtime_enabled_features.json5",
-             "../build/scripts/templates/runtime_feature_state_override_context.h.tmpl",
-             "../build/scripts/templates/runtime_feature_state_override_context.cc.tmpl",
-           ]
-  outputs = [
-    "$blink_core_output_dir/runtime_feature_state/runtime_feature_state_override_context.h",
-    "$blink_core_output_dir/runtime_feature_state/runtime_feature_state_override_context.cc",
-  ]
-
-  args = [
-    rebase_path("../platform/runtime_enabled_features.json5", root_build_dir),
-    "--output_dir",
-    "$rel_blink_core_gen_dir/runtime_feature_state",
-  ]
-}
-
 blink_python_runner("make_core_generated_web_origin_trials") {
   script = "../build/scripts/make_web_origin_trials.py"
 
@@ -1211,7 +1189,6 @@
   ":make_core_generated_performance_entry_names",
   ":make_core_generated_permissions_policy_helper",
   ":make_core_generated_pointer_type_names",
-  ":make_core_generated_runtime_feature_state_override_context",
   ":make_core_generated_script_type_names",
   ":make_core_generated_securitypolicyviolation_disposition_names",
   ":make_core_generated_shadow_element_names",
diff --git a/third_party/blink/renderer/core/css/transition_animations.css b/third_party/blink/renderer/core/css/transition_animations.css
index 9d08592..bac196bb 100644
--- a/third_party/blink/renderer/core/css/transition_animations.css
+++ b/third_party/blink/renderer/core/css/transition_animations.css
@@ -9,6 +9,12 @@
 
 @namespace "http://www.w3.org/1999/xhtml";
 
+
+html::view-transition-group(*) {
+  animation-duration: 0.25s;
+  animation-fill-mode: both;
+}
+
 @keyframes -ua-view-transition-fade-in {
   from {
     opacity: 0;
@@ -16,7 +22,9 @@
 }
 
 html::view-transition-new(*) {
-  animation: -ua-view-transition-fade-in 0.25s both;
+  animation-name: -ua-view-transition-fade-in;
+  animation-duration: inherit;
+  animation-fill-mode: inherit;
 }
 
 @keyframes -ua-view-transition-fade-out {
@@ -26,5 +34,12 @@
 }
 
 html::view-transition-old(*) {
-  animation: -ua-view-transition-fade-out 0.25s both;
+  animation-name: -ua-view-transition-fade-out;
+  animation-duration: inherit;
+  animation-fill-mode: inherit;
+}
+
+html::view-transition-image-pair(*) {
+  animation-duration: inherit;
+  animation-fill-mode: inherit;
 }
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 4e9b55c..15cf97e 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -1946,7 +1946,7 @@
   EXPECT_TRUE(locked_object->DescendantNeedsPaintPropertyUpdate());
   EXPECT_FALSE(handler_object->DescendantNeedsPaintPropertyUpdate());
 
-  locked_object->SetShouldCheckForPaintInvalidationWithoutGeometryChange();
+  locked_object->SetShouldCheckForPaintInvalidationWithoutLayoutChange();
   UpdateAllLifecyclePhasesForTest();
 
   EXPECT_FALSE(ancestor_object->NeedsPaintPropertyUpdate());
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index efb92b84..25451a7e8 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -974,8 +974,6 @@
 
   void ResetForceLegacyLayoutForPrinting();
 
-  virtual void BuildPendingResource() {}
-
   void SetCustomElementDefinition(CustomElementDefinition*);
   CustomElementDefinition* GetCustomElementDefinition() const;
   // https://dom.spec.whatwg.org/#concept-element-is-value
diff --git a/third_party/blink/renderer/core/editing/compare_positions.cc b/third_party/blink/renderer/core/editing/compare_positions.cc
index c2fc639..de782d1 100644
--- a/third_party/blink/renderer/core/editing/compare_positions.cc
+++ b/third_party/blink/renderer/core/editing/compare_positions.cc
@@ -33,11 +33,11 @@
 namespace {
 
 template <typename Traversal>
-int16_t ComparePositions(const Node* container_a,
-                         int offset_a,
-                         const Node* container_b,
-                         int offset_b,
-                         bool* disconnected) {
+int16_t SlowComparePositions(const Node* container_a,
+                             int offset_a,
+                             const Node* container_b,
+                             int offset_b,
+                             bool* disconnected) {
   DCHECK(container_a);
   DCHECK(container_b);
 
@@ -130,6 +130,162 @@
   return 0;
 }
 
+// The `Comparator` class implements `ComparePositions()` logic.
+template <typename Traversal>
+class Comparator {
+  STATIC_ONLY(Comparator);
+
+ public:
+  // Returns
+  //  -1 if `node_a` is before `node_b`
+  //   0 if `node_a == node_b`
+  //   1 if `node_a` is after `node_b`
+  //    where
+  //      * `node_a == Traversal::ChildAt(*container_a, offset_a)`
+  //      * `node_b == Traversal::ChildAt(*container_a, offset_b)`
+  // and set `disconnected` to true if `node_a` and `node_b` are in different
+  // tree scopes.
+  static int16_t ComparePositions(const Node* container_a,
+                                  int offset_a,
+                                  const Node* container_b,
+                                  int offset_b,
+                                  bool* disconnected) {
+    DCHECK(container_a);
+    DCHECK(container_b);
+
+    if (disconnected)
+      *disconnected = false;
+
+    if (!container_a)
+      return kAIsBeforeB;
+    if (!container_b)
+      return kAIsAfterB;
+
+    // see DOM2 traversal & range section 2.5
+
+    // Case 1: both points have the same container
+    if (container_a == container_b) {
+      if (offset_a == offset_b)
+        return kAIsEqualToB;
+      if (offset_a < offset_b)
+        return kAIsBeforeB;
+      return kAIsAfterB;
+    }
+
+    // Case 2: node C (container B or an ancestor) is a child node of A, e.g.
+    //  * A < B
+    //      `<a>...A...<c2>...<b>...B...</b>...</c2>...</a>`
+    //  * A > B
+    //      `<a>...<c2>...<b>...B...</b>...</c2>...A...</a>`
+    //  * A == C2
+    //             A
+    //      `<a>...<c2>...<b>...B...</b>...</c2>...</a>`
+    if (const Node* node_c2 = FindChildnInAncestors(*container_b, *container_a))
+      return CompareNodesInSameParent(offset_a, node_c2, kAIsBeforeB);
+
+    // Case 3: node C (container A or an ancestor) is a child node of B, e.g.
+    //  * B < A
+    //      `<b>...B....<c3>...<a>...A...</a>...</b>`
+    //  * B > A
+    //      `<b>...<c3>...<a>...A...</a>...</c3>...B...</b>`
+    //  * B == C3
+    //             B
+    //      `<b>...<c3>...<a>...A...</a>...</b>`
+    if (const Node* node_c3 = FindChildnInAncestors(*container_a, *container_b))
+      return -CompareNodesInSameParent(offset_b, node_c3, kAIsBeforeB);
+
+    // case 4: containers A & B are siblings, or children of siblings
+    // ### we need to do a traversal here instead
+    Node* const common_ancestor =
+        Traversal::CommonAncestor(*container_a, *container_b);
+    if (!common_ancestor) {
+      if (disconnected)
+        *disconnected = true;
+      return kAIsEqualToB;
+    }
+
+    const Node* const child_a =
+        FindChildnInAncestors(*container_a, *common_ancestor);
+    const Node* const adjusted_child_a =
+        child_a ? child_a : Traversal::LastChild(*common_ancestor);
+    const Node* const child_b =
+        FindChildnInAncestors(*container_b, *common_ancestor);
+    const Node* const adjusted_child_b =
+        child_b ? child_b : Traversal::LastChild(*common_ancestor);
+    return CompareNodesInSameParent(adjusted_child_a, adjusted_child_b);
+  }
+
+ private:
+  enum Result : int16_t {
+    kAIsBeforeB = -1,
+    kAIsEqualToB = 0,
+    kAIsAfterB = 1,
+  };
+
+  // Returns where `offset_b =  Traversal::Index(*child_b)`:
+  //  -1 if `offset_a < offset_b`
+  //   0 if `offset_a == offset_b`
+  //   1 if `offset_a > offset_b`
+  // The number of iteration is `std::min(offset_a, offset_b)`.
+  static Result CompareNodesInSameParent(
+      int offset_a,
+      const Node* child_b,
+      Result result_of_a_is_equal_to_b = kAIsEqualToB) {
+    DCHECK(child_b);
+    int offset_b = 0;
+    for (const Node& child_a :
+         Traversal::ChildrenOf(*Traversal::Parent(*child_b))) {
+      if (child_a == child_b || offset_a == offset_b) {
+        const int diff = offset_a - offset_b;
+        return !diff      ? result_of_a_is_equal_to_b
+               : diff > 0 ? kAIsAfterB
+                          : kAIsBeforeB;
+      }
+      ++offset_b;
+    }
+    NOTREACHED();
+    return result_of_a_is_equal_to_b;
+  }
+
+  // Returns
+  //  -1 if `Traversal::Index(*child_a) < Traversal::Index(*child_b)`
+  //   0 if `Traversal::Index(*child_a) == Traversal::Index(*child_b)`
+  //   1 if `Traversal::Index(*child_a) > Traversal::Index(*child_b)`
+  // The number of iteration is `std::min(offset_a, offset_b)`.
+  static Result CompareNodesInSameParent(
+      const Node* child_a,
+      const Node* child_b,
+      Result result_of_a_is_equal_to_b = kAIsEqualToB) {
+    DCHECK(child_a);
+    DCHECK(child_b);
+    if (child_a == child_b)
+      return result_of_a_is_equal_to_b;
+    DCHECK_EQ(Traversal::Parent(*child_a), Traversal::Parent(*child_b));
+    for (const Node& child :
+         Traversal::ChildrenOf(*Traversal::Parent(*child_a))) {
+      if (child == child_a)
+        return child == child_b ? result_of_a_is_equal_to_b : kAIsBeforeB;
+      if (child == child_b)
+        return kAIsAfterB;
+    }
+    NOTREACHED();
+    return result_of_a_is_equal_to_b;
+  }
+
+  // Returns the child node in `parent` if `parent` is one of inclusive
+  // ancestors of `node`, otherwise `nullptr`.
+  // See https://dom.spec.whatwg.org/#boundary-points
+  static const Node* FindChildnInAncestors(const Node& node,
+                                           const Node& parent) {
+    DCHECK_NE(node, parent);
+    for (const Node& child : Traversal::InclusiveAncestorsOf(node)) {
+      if (Traversal::Parent(child) == parent)
+        return &child;
+    }
+    return nullptr;
+  }
+};
+
 }  // namespace
 
 int16_t ComparePositionsInDOMTree(const Node* container_a,
@@ -137,8 +293,13 @@
                                   const Node* container_b,
                                   int offset_b,
                                   bool* disconnected) {
-  return ComparePositions<NodeTraversal>(container_a, offset_a, container_b,
-                                         offset_b, disconnected);
+  if (!RuntimeEnabledFeatures::FastComparePositionsEnabled()) {
+    return SlowComparePositions<NodeTraversal>(
+        container_a, offset_a, container_b, offset_b, disconnected);
+  }
+
+  return Comparator<NodeTraversal>::ComparePositions(
+      container_a, offset_a, container_b, offset_b, disconnected);
 }
 
 int16_t ComparePositionsInFlatTree(const Node* container_a,
@@ -146,8 +307,13 @@
                                    const Node* container_b,
                                    int offset_b,
                                    bool* disconnected) {
-  return ComparePositions<FlatTreeTraversal>(container_a, offset_a, container_b,
-                                             offset_b, disconnected);
+  if (!RuntimeEnabledFeatures::FastComparePositionsEnabled()) {
+    return SlowComparePositions<FlatTreeTraversal>(
+        container_a, offset_a, container_b, offset_b, disconnected);
+  }
+
+  return Comparator<FlatTreeTraversal>::ComparePositions(
+      container_a, offset_a, container_b, offset_b, disconnected);
 }
 
 // Compare two positions, taking into account the possibility that one or both
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc
index 485f7de3..cc4856e 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.cc
+++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -60,6 +60,7 @@
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/loader/fetch/code_cache_host.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
+#include "third_party/blink/renderer/platform/runtime_feature_state/runtime_feature_state_override_context.h"
 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
@@ -76,7 +77,9 @@
       lifecycle_state_(mojom::FrameLifecycleState::kRunning),
       csp_delegate_(MakeGarbageCollected<ExecutionContextCSPDelegate>(*this)),
       window_interaction_tokens_(0),
-      origin_trial_context_(MakeGarbageCollected<OriginTrialContext>(this)) {
+      origin_trial_context_(MakeGarbageCollected<OriginTrialContext>(this)),
+      runtime_feature_state_override_context_(
+          MakeGarbageCollected<RuntimeFeatureStateOverrideContext>()) {
   DCHECK(agent_);
 }
 
@@ -552,6 +555,7 @@
   visitor->Trace(timers_);
   visitor->Trace(origin_trial_context_);
   visitor->Trace(content_security_policy_);
+  visitor->Trace(runtime_feature_state_override_context_);
   MojoBindingContext::Trace(visitor);
   ConsoleLogger::Trace(visitor);
   Supplementable<ExecutionContext>::Trace(visitor);
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h
index 0ebaa4e..08a061e 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -94,6 +94,7 @@
 class KURL;
 class LocalDOMWindow;
 class OriginTrialContext;
+class RuntimeFeatureStateOverrideContext;
 class PolicyContainer;
 class PublicURLManager;
 class ResourceFetcher;
@@ -346,6 +347,11 @@
     return origin_trial_context_;
   }
 
+  RuntimeFeatureStateOverrideContext* GetRuntimeFeatureStateOverrideContext()
+      const override {
+    return runtime_feature_state_override_context_;
+  }
+
   virtual TrustedTypePolicyFactory* GetTrustedTypes() const { return nullptr; }
   virtual bool RequireTrustedTypes() const;
 
@@ -539,6 +545,10 @@
   Member<OriginTrialContext> origin_trial_context_;
 
   Member<ContentSecurityPolicy> content_security_policy_;
+
+  Member<RuntimeFeatureStateOverrideContext>
+      runtime_feature_state_override_context_;
+
   bool require_safe_types_ = false;
 };
 
diff --git a/third_party/blink/renderer/core/frame/history.cc b/third_party/blink/renderer/core/frame/history.cc
index bba55ca..33dc128 100644
--- a/third_party/blink/renderer/core/frame/history.cc
+++ b/third_party/blink/renderer/core/frame/history.cc
@@ -57,7 +57,7 @@
                      const String& url) {
   DCHECK(window);
   DCHECK(window->GetFrame());
-  if (window->GetFrame()->IsMainFrame()) {
+  if (window->GetFrame()->IsMainFrame() && window->Url() != url) {
     SoftNavigationHeuristics* heuristics =
         SoftNavigationHeuristics::From(*window);
     heuristics->SawURLChange(script_state, url);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 589661f..e8257f4b 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1846,9 +1846,7 @@
     if (!target_domain.empty() && !destination_domain.empty() &&
         target_domain == destination_domain &&
         (target_frame.GetSecurityContext()->GetSecurityOrigin()->Protocol() ==
-             destination_url.Protocol() ||
-         !base::FeatureList::IsEnabled(
-             features::kBlockCrossOriginTopNavigationToDiffentScheme))) {
+             destination_url.Protocol())) {
       return true;
     }
 
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 fa798b2..2132094 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
@@ -1619,6 +1619,10 @@
   widget_base_->SetVisibleViewportSizeInDIPs(
       visual_properties.visible_viewport_size);
 
+  virtual_keyboard_resize_height_physical_px_ =
+      visual_properties.virtual_keyboard_resize_height_physical_px;
+  DCHECK(!virtual_keyboard_resize_height_physical_px_ || ForTopMostMainFrame());
+
   if (ForMainFrame()) {
     if (!AutoResizeMode()) {
       size_ = widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size);
@@ -4381,6 +4385,11 @@
       may_throttle_if_undrawn_frames);
 }
 
+int WebFrameWidgetImpl::GetVirtualKeyboardResizeHeight() const {
+  DCHECK(!virtual_keyboard_resize_height_physical_px_ || ForTopMostMainFrame());
+  return virtual_keyboard_resize_height_physical_px_;
+}
+
 bool WebFrameWidgetImpl::GetMayThrottleIfUndrawnFramesForTesting() {
   return widget_base_->LayerTreeHost()
       ->GetMayThrottleIfUndrawnFramesForTesting();
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
index e511842..ba78ca7 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -312,6 +312,8 @@
   void SetLayerTreeDebugState(const cc::LayerTreeDebugState& state) override;
   void SetMayThrottleIfUndrawnFrames(
       bool may_throttle_if_undrawn_frames) override;
+  int GetVirtualKeyboardResizeHeight() const override;
+
   bool GetMayThrottleIfUndrawnFramesForTesting();
 
   // WebFrameWidget overrides.
@@ -949,6 +951,10 @@
   // than the WebViewImpl::size_ since isn't set in auto resize mode.
   absl::optional<gfx::Size> size_;
 
+  // The amount the top-most widget has been resized by the virtual keyboard,
+  // in physical pixels.
+  int virtual_keyboard_resize_height_physical_px_ = 0;
+
   static bool ignore_input_events_;
 
   const viz::FrameSinkId frame_sink_id_;
diff --git a/third_party/blink/renderer/core/inspector/devtools_agent.cc b/third_party/blink/renderer/core/inspector/devtools_agent.cc
index c6705680..67e846d 100644
--- a/third_party/blink/renderer/core/inspector/devtools_agent.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_agent.cc
@@ -109,14 +109,15 @@
       mojom::blink::DevToolsSessionStatePtr reattach_session_state,
       bool client_expects_binary_responses,
       bool client_is_trusted,
-      const WTF::String& session_id) override {
+      const WTF::String& session_id,
+      bool session_waits_for_debugger) override {
     DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
     DCHECK(receiver_.is_bound());
     inspector_task_runner_->AppendTask(CrossThreadBindOnce(
         &::blink::DevToolsAgent::AttachDevToolsSessionImpl, agent_,
         std::move(host), std::move(main_session), std::move(io_session),
         std::move(reattach_session_state), client_expects_binary_responses,
-        client_is_trusted, session_id));
+        client_is_trusted, session_id, session_waits_for_debugger));
   }
 
   void InspectElement(const gfx::Point& point) override {
@@ -224,13 +225,15 @@
     mojom::blink::DevToolsSessionStatePtr reattach_session_state,
     bool client_expects_binary_responses,
     bool client_is_trusted,
-    const WTF::String& session_id) {
+    const WTF::String& session_id,
+    bool session_waits_for_debugger) {
   TRACE_EVENT0("devtools", "Agent::AttachDevToolsSessionImpl");
   client_->DebuggerTaskStarted();
   DevToolsSession* session = MakeGarbageCollected<DevToolsSession>(
       this, std::move(host), std::move(session_receiver),
       std::move(io_session_receiver), std::move(reattach_session_state),
       client_expects_binary_responses, client_is_trusted, session_id,
+      session_waits_for_debugger,
       inspector_task_runner_->isolate_task_runner());
   sessions_.insert(session);
   client_->DebuggerTaskFinished();
@@ -244,18 +247,23 @@
     mojom::blink::DevToolsSessionStatePtr reattach_session_state,
     bool client_expects_binary_responses,
     bool client_is_trusted,
-    const WTF::String& session_id) {
+    const WTF::String& session_id,
+    bool session_waits_for_debugger) {
   TRACE_EVENT0("devtools", "Agent::AttachDevToolsSession");
   if (associated_receiver_.is_bound()) {
+    // Discard `session_waits_for_debugger` for regular pages, this is rather
+    // handled by the navigation throttles machinery on the browser side.
     AttachDevToolsSessionImpl(
         std::move(host), std::move(session_receiver),
         std::move(io_session_receiver), std::move(reattach_session_state),
-        client_expects_binary_responses, client_is_trusted, session_id);
+        client_expects_binary_responses, client_is_trusted, session_id,
+        /* session_waits_for_debugger */ false);
   } else {
     io_agent_->AttachDevToolsSession(
         std::move(host), std::move(session_receiver),
         std::move(io_session_receiver), std::move(reattach_session_state),
-        client_expects_binary_responses, client_is_trusted, session_id);
+        client_expects_binary_responses, client_is_trusted, session_id,
+        session_waits_for_debugger);
   }
 }
 
diff --git a/third_party/blink/renderer/core/inspector/devtools_agent.h b/third_party/blink/renderer/core/inspector/devtools_agent.h
index fa95f29..3aa838d 100644
--- a/third_party/blink/renderer/core/inspector/devtools_agent.h
+++ b/third_party/blink/renderer/core/inspector/devtools_agent.h
@@ -97,7 +97,8 @@
       mojom::blink::DevToolsSessionStatePtr reattach_session_state,
       bool client_expects_binary_responses,
       bool client_is_trusted,
-      const WTF::String& session_id) override;
+      const WTF::String& session_id,
+      bool session_waits_for_debugger) override;
   void InspectElement(const gfx::Point& point) override;
   void ReportChildTargets(bool report,
                           bool wait_for_debugger,
@@ -128,7 +129,8 @@
       mojom::blink::DevToolsSessionStatePtr reattach_session_state,
       bool client_expects_binary_responses,
       bool client_is_trusted,
-      const WTF::String& session_id);
+      const WTF::String& session_id,
+      bool session_waits_for_debugger);
   void InspectElementImpl(const gfx::Point& point);
   void ReportChildTargetsImpl(bool report,
                               bool wait_for_debugger,
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.cc b/third_party/blink/renderer/core/inspector/devtools_session.cc
index d9274f6..0718aa7 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_session.cc
@@ -122,6 +122,7 @@
     bool client_expects_binary_responses,
     bool client_is_trusted,
     const String& session_id,
+    bool session_waits_for_debugger,
     scoped_refptr<base::SequencedTaskRunner> mojo_task_runner)
     : agent_(agent),
       inspector_backend_dispatcher_(new protocol::UberDispatcher(this)),
@@ -130,7 +131,8 @@
       client_is_trusted_(client_is_trusted),
       v8_session_state_(kV8StateKey),
       v8_session_state_cbor_(&v8_session_state_, /*default_value=*/{}),
-      session_id_(session_id) {
+      session_id_(session_id),
+      session_waits_for_debugger_(session_waits_for_debugger) {
   receiver_.Bind(std::move(main_receiver), mojo_task_runner);
 
   io_session_ = new IOSession(
@@ -162,7 +164,10 @@
       context_group_id, this,
       v8_inspector::StringView(cbor.data(), cbor.size()),
       client_is_trusted_ ? v8_inspector::V8Inspector::kFullyTrusted
-                         : v8_inspector::V8Inspector::kUntrusted);
+                         : v8_inspector::V8Inspector::kUntrusted,
+      session_waits_for_debugger_
+          ? v8_inspector::V8Inspector::kWaitingForDebugger
+          : v8_inspector::V8Inspector::kNotWaitingForDebugger);
 }
 
 bool DevToolsSession::IsDetached() {
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.h b/third_party/blink/renderer/core/inspector/devtools_session.h
index 30efb21f..5e655e70 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.h
+++ b/third_party/blink/renderer/core/inspector/devtools_session.h
@@ -64,6 +64,7 @@
       bool client_expects_binary_responses,
       bool client_is_trusted,
       const String& session_id,
+      bool session_waits_for_debugger,
       scoped_refptr<base::SequencedTaskRunner> mojo_task_runner);
   DevToolsSession(const DevToolsSession&) = delete;
   DevToolsSession& operator=(const DevToolsSession&) = delete;
@@ -171,6 +172,9 @@
   InspectorAgentState v8_session_state_;
   InspectorAgentState::Bytes v8_session_state_cbor_;
   const String session_id_;
+  // This is only relevant until the initial attach to v8 and is never reset
+  // once the session stops waiting.
+  const bool session_waits_for_debugger_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 7800182..60ed093 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2793,13 +2793,13 @@
       (StyleRef().MaskBoxImage().GetImage() &&
        StyleRef().MaskBoxImage().GetImage()->Data() == image) ||
       is_box_reflect_image) {
-    SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+    SetShouldDoFullPaintInvalidationWithoutLayoutChange(
         PaintInvalidationReason::kImage);
   } else {
     for (const FillLayer* layer = &StyleRef().MaskLayers(); layer;
          layer = layer->Next()) {
       if (layer->GetImage() && image == layer->GetImage()->Data()) {
-        SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+        SetShouldDoFullPaintInvalidationWithoutLayoutChange(
             PaintInvalidationReason::kImage);
         break;
       }
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc
index 49abe197..1f7791a 100644
--- a/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -204,7 +204,7 @@
     }
   }
 
-  SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+  SetShouldDoFullPaintInvalidationWithoutLayoutChange(
       PaintInvalidationReason::kImage);
 
   if (defer == CanDeferInvalidation::kYes && ImageResource() &&
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index d237ff5b..9fe869b 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -1905,8 +1905,8 @@
   if (!Parent())
     return;
 
-  // FIXME: We can do better.
-  SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kImage);
+  SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+      PaintInvalidationReason::kImage);
 }
 
 void LayoutInline::AddOutlineRects(
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
index d51c0a4..23ce55490 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -634,8 +634,7 @@
   NOT_DESTROYED();
   for (LayoutMultiColumnSet* column_set = FirstMultiColumnSet(); column_set;
        column_set = column_set->NextSiblingMultiColumnSet()) {
-    column_set->SetShouldDoFullPaintInvalidation(
-        PaintInvalidationReason::kStyle);
+    column_set->SetShouldDoFullPaintInvalidation();
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 3357e07..820f911 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -2696,6 +2696,8 @@
           text->InvalidateVisualOverflow();
       }
       PaintingLayer()->SetNeedsVisualOverflowRecalc();
+      // TODO(crbug.com/1385848): This looks like an over-invalidation.
+      // visual overflow change should not require checking for layout change.
       SetShouldCheckForPaintInvalidation();
     }
 #if DCHECK_IS_ON()
@@ -2710,7 +2712,8 @@
     } else {
       // We'll set needing geometry change later if the style change does cause
       // possible layout change or visual overflow change.
-      SetShouldDoFullPaintInvalidationWithoutGeometryChange();
+      SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+          PaintInvalidationReason::kStyle);
     }
   }
 
@@ -2740,7 +2743,8 @@
   }
 
   if (!IsText() && diff.CompositablePaintEffectChanged()) {
-    SetShouldDoFullPaintInvalidationWithoutGeometryChange();
+    SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+        PaintInvalidationReason::kStyle);
   }
 }
 
@@ -4564,63 +4568,54 @@
 void LayoutObject::SetShouldDoFullPaintInvalidation(
     PaintInvalidationReason reason) {
   NOT_DESTROYED();
+  DCHECK(IsLayoutPaintInvalidationReason(reason));
   SetShouldCheckForPaintInvalidation();
-  SetShouldDoFullPaintInvalidationWithoutGeometryChange(reason);
+  SetShouldDoFullPaintInvalidationWithoutLayoutChangeInternal(reason);
 }
 
-static PaintInvalidationReason DocumentLifecycleBasedPaintInvalidationReason(
-    const DocumentLifecycle& document_lifecycle) {
-  switch (document_lifecycle.GetState()) {
-    case DocumentLifecycle::kInStyleRecalc:
-      return PaintInvalidationReason::kStyle;
-    case DocumentLifecycle::kInPerformLayout:
-    case DocumentLifecycle::kAfterPerformLayout:
-      return PaintInvalidationReason::kGeometry;
-    default:
-      return PaintInvalidationReason::kFull;
-  }
+void LayoutObject::SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+    PaintInvalidationReason reason) {
+  NOT_DESTROYED();
+  DCHECK(IsNonLayoutFullPaintInvalidationReason(reason));
+  // Use SetBackgroundNeedsFullPaintInvalidation() instead. See comment of the
+  // function.
+  DCHECK_NE(reason, PaintInvalidationReason::kBackground);
+  SetShouldDoFullPaintInvalidationWithoutLayoutChangeInternal(reason);
 }
 
-void LayoutObject::
-    SetShouldDoFullPaintInvalidationWithoutGeometryChangeInternal(
-        PaintInvalidationReason reason) {
+void LayoutObject::SetShouldDoFullPaintInvalidationWithoutLayoutChangeInternal(
+    PaintInvalidationReason reason) {
   NOT_DESTROYED();
   // Only full invalidation reasons are allowed.
   DCHECK(IsFullPaintInvalidationReason(reason));
-  if (ShouldDoFullPaintInvalidation())
-    return;
-
-  SetShouldCheckForPaintInvalidationWithoutGeometryChange();
-  if (reason == PaintInvalidationReason::kFull) {
-    reason = DocumentLifecycleBasedPaintInvalidationReason(
-        GetDocument().Lifecycle());
-  }
-  full_paint_invalidation_reason_ = static_cast<unsigned>(reason);
-  DCHECK_EQ(reason, FullPaintInvalidationReason());
   bitfields_.SetShouldDelayFullPaintInvalidation(false);
+  if (reason > FullPaintInvalidationReason()) {
+    SetShouldCheckForPaintInvalidationWithoutLayoutChange();
+    full_paint_invalidation_reason_ = static_cast<unsigned>(reason);
+    DCHECK_EQ(reason, FullPaintInvalidationReason());
+  }
 }
 
 void LayoutObject::SetShouldCheckForPaintInvalidation() {
   NOT_DESTROYED();
-  if (ShouldCheckGeometryForPaintInvalidation()) {
+  if (ShouldCheckLayoutForPaintInvalidation()) {
     DCHECK(ShouldCheckForPaintInvalidation());
     return;
   }
   GetFrameView()->ScheduleVisualUpdateForPaintInvalidationIfNeeded();
 
   bitfields_.SetShouldCheckForPaintInvalidation(true);
-  bitfields_.SetShouldCheckGeometryForPaintInvalidation(true);
+  bitfields_.SetShouldCheckLayoutForPaintInvalidation(true);
   for (LayoutObject* ancestor = Parent();
-       ancestor &&
-       !ancestor->DescendantShouldCheckGeometryForPaintInvalidation();
+       ancestor && !ancestor->DescendantShouldCheckLayoutForPaintInvalidation();
        ancestor = ancestor->Parent()) {
     ancestor->bitfields_.SetShouldCheckForPaintInvalidation(true);
-    ancestor->bitfields_.SetDescendantShouldCheckGeometryForPaintInvalidation(
+    ancestor->bitfields_.SetDescendantShouldCheckLayoutForPaintInvalidation(
         true);
   }
 }
 
-void LayoutObject::SetShouldCheckForPaintInvalidationWithoutGeometryChange() {
+void LayoutObject::SetShouldCheckForPaintInvalidationWithoutLayoutChange() {
   NOT_DESTROYED();
   if (ShouldCheckForPaintInvalidation())
     return;
@@ -4649,7 +4644,7 @@
   if (MayNeedPaintInvalidationAnimatedBackgroundImage())
     return;
   bitfields_.SetMayNeedPaintInvalidationAnimatedBackgroundImage(true);
-  SetShouldCheckForPaintInvalidationWithoutGeometryChange();
+  SetShouldCheckForPaintInvalidationWithoutLayoutChange();
 }
 
 void LayoutObject::SetShouldDelayFullPaintInvalidation() {
@@ -4660,7 +4655,7 @@
   bitfields_.SetShouldDelayFullPaintInvalidation(true);
   if (!ShouldCheckForPaintInvalidation()) {
     // This will also schedule a visual update.
-    SetShouldCheckForPaintInvalidationWithoutGeometryChange();
+    SetShouldCheckForPaintInvalidationWithoutLayoutChange();
   } else {
     // Schedule visual update for the next document cycle in which we will
     // check if the delayed invalidation should be promoted to a real
@@ -4670,9 +4665,8 @@
 }
 
 void LayoutObject::ClearShouldDelayFullPaintInvalidation() {
-  // This will clear ShouldDelayFullPaintInvalidation() flag and enable previous
-  // BackgroundNeedsFullPaintInvalidaiton() if it's set.
-  SetShouldDoFullPaintInvalidationWithoutGeometryChangeInternal(
+  // This will clear ShouldDelayFullPaintInvalidation() flag.
+  SetShouldDoFullPaintInvalidationWithoutLayoutChangeInternal(
       FullPaintInvalidationReason());
 }
 
@@ -4692,8 +4686,8 @@
   bitfields_.SetSubtreeShouldCheckForPaintInvalidation(false);
   bitfields_.SetSubtreeShouldDoFullPaintInvalidation(false);
   bitfields_.SetMayNeedPaintInvalidationAnimatedBackgroundImage(false);
-  bitfields_.SetShouldCheckGeometryForPaintInvalidation(false);
-  bitfields_.SetDescendantShouldCheckGeometryForPaintInvalidation(false);
+  bitfields_.SetShouldCheckLayoutForPaintInvalidation(false);
+  bitfields_.SetDescendantShouldCheckLayoutForPaintInvalidation(false);
   bitfields_.SetShouldInvalidateSelection(false);
 }
 
@@ -4702,8 +4696,8 @@
   NOT_DESTROYED();
   return BackgroundNeedsFullPaintInvalidation() ||
          ShouldCheckForPaintInvalidation() || ShouldInvalidateSelection() ||
-         ShouldCheckGeometryForPaintInvalidation() ||
-         DescendantShouldCheckGeometryForPaintInvalidation() ||
+         ShouldCheckLayoutForPaintInvalidation() ||
+         DescendantShouldCheckLayoutForPaintInvalidation() ||
          ShouldDoFullPaintInvalidation() ||
          SubtreeShouldDoFullPaintInvalidation() ||
          MayNeedPaintInvalidationAnimatedBackgroundImage();
@@ -4718,7 +4712,7 @@
   // and this object is marked for checking paint invalidation for any reason.
   if (bitfields_.OutlineMayBeAffectedByDescendants() ||
       bitfields_.PreviousOutlineMayBeAffectedByDescendants()) {
-    SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+    SetShouldDoFullPaintInvalidationWithoutLayoutChange(
         PaintInvalidationReason::kOutline);
   }
   bitfields_.SetPreviousOutlineMayBeAffectedByDescendants(
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index f7438b1..a6f6c9f7 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -3152,14 +3152,9 @@
   // background needs full invalidation, use
   // SetBackgroundNeedsFullPaintInvalidation().
   void SetShouldDoFullPaintInvalidation(
-      PaintInvalidationReason = PaintInvalidationReason::kFull);
-  void SetShouldDoFullPaintInvalidationWithoutGeometryChange(
-      PaintInvalidationReason reason = PaintInvalidationReason::kFull) {
-    NOT_DESTROYED();
-    // Use SetBackgroundNeedsFullPaintInvalidation() instead. See comment above.
-    DCHECK_NE(reason, PaintInvalidationReason::kBackground);
-    SetShouldDoFullPaintInvalidationWithoutGeometryChangeInternal(reason);
-  }
+      PaintInvalidationReason = PaintInvalidationReason::kLayout);
+  void SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+      PaintInvalidationReason reason);
 
   void ClearPaintInvalidationFlags();
 
@@ -3168,13 +3163,13 @@
     return bitfields_.ShouldCheckForPaintInvalidation();
   }
   // Sets both ShouldCheckForPaintInvalidation() and
-  // ShouldCheckGeometryForPaintInvalidation(). Though the setter and the getter
+  // ShouldCheckLayoutForPaintInvalidation(). Though the setter and the getter
   // are asymmetric, this prevents callers from accidentally missing the
-  // geometry checking flag.
+  // layout checking flag.
   void SetShouldCheckForPaintInvalidation();
   // Sets ShouldCheckForPaintInvalidation() only. PaintInvalidator won't require
-  // paint property tree update or other geometry related updates.
-  void SetShouldCheckForPaintInvalidationWithoutGeometryChange();
+  // paint property tree update or other layout related updates.
+  void SetShouldCheckForPaintInvalidationWithoutLayoutChange();
 
   bool SubtreeShouldCheckForPaintInvalidation() const {
     NOT_DESTROYED();
@@ -3182,13 +3177,13 @@
   }
   void SetSubtreeShouldCheckForPaintInvalidation();
 
-  bool ShouldCheckGeometryForPaintInvalidation() const {
+  bool ShouldCheckLayoutForPaintInvalidation() const {
     NOT_DESTROYED();
-    return bitfields_.ShouldCheckGeometryForPaintInvalidation();
+    return bitfields_.ShouldCheckLayoutForPaintInvalidation();
   }
-  bool DescendantShouldCheckGeometryForPaintInvalidation() const {
+  bool DescendantShouldCheckLayoutForPaintInvalidation() const {
     NOT_DESTROYED();
-    return bitfields_.DescendantShouldCheckGeometryForPaintInvalidation();
+    return bitfields_.DescendantShouldCheckLayoutForPaintInvalidation();
   }
 
   bool MayNeedPaintInvalidationAnimatedBackgroundImage() const {
@@ -3352,29 +3347,29 @@
     void SetShouldCheckForPaintInvalidation() {
       DCHECK_EQ(layout_object_.GetDocument().Lifecycle().GetState(),
                 DocumentLifecycle::kInPrePaint);
-      layout_object_.bitfields_.SetShouldCheckGeometryForPaintInvalidation(
-          true);
+      layout_object_.bitfields_.SetShouldCheckLayoutForPaintInvalidation(true);
       layout_object_.bitfields_.SetShouldCheckForPaintInvalidation(true);
     }
     void SetShouldDoFullPaintInvalidation(PaintInvalidationReason reason) {
       DCHECK_EQ(layout_object_.GetDocument().Lifecycle().GetState(),
                 DocumentLifecycle::kInPrePaint);
-      if (layout_object_.ShouldDoFullPaintInvalidation())
-        return;
-      SetShouldDoFullPaintInvalidationWithoutGeometryChange(reason);
-      layout_object_.bitfields_.SetShouldCheckGeometryForPaintInvalidation(
-          true);
+      // This call to MutableForPainting::SetShouldCheckForPaintInvaldiation()
+      // prevents LayoutObject::SetShouldDoFullPaintInvalidation() from marking
+      // ancestors for paint invalidation, which is not needed when this is
+      // called during PrePaint.
+      SetShouldCheckForPaintInvalidation();
+      layout_object_.SetShouldDoFullPaintInvalidation(reason);
     }
-    void SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+    void SetShouldDoFullPaintInvalidationWithoutLayoutChange(
         PaintInvalidationReason reason) {
       DCHECK_EQ(layout_object_.GetDocument().Lifecycle().GetState(),
                 DocumentLifecycle::kInPrePaint);
-      if (layout_object_.ShouldDoFullPaintInvalidation())
-        return;
+      DCHECK(IsNonLayoutFullPaintInvalidationReason(reason));
+      // This prevents LayoutObject::SetShouldDoFullPaintInvalidation...()
+      // from marking ancestors for paint invalidation.
       layout_object_.bitfields_.SetShouldCheckForPaintInvalidation(true);
-      layout_object_.bitfields_.SetShouldDelayFullPaintInvalidation(false);
-      layout_object_.full_paint_invalidation_reason_ =
-          static_cast<unsigned>(reason);
+      layout_object_
+          .SetShouldDoFullPaintInvalidationWithoutLayoutChangeInternal(reason);
     }
 
     void SetShouldDelayFullPaintInvalidation() {
@@ -3543,7 +3538,7 @@
   }
   void SetBackgroundNeedsFullPaintInvalidation() {
     NOT_DESTROYED();
-    SetShouldDoFullPaintInvalidationWithoutGeometryChangeInternal(
+    SetShouldDoFullPaintInvalidationWithoutLayoutChangeInternal(
         PaintInvalidationReason::kBackground);
     bitfields_.SetBackgroundNeedsFullPaintInvalidation(true);
   }
@@ -3999,7 +3994,7 @@
 
   void MarkSelfPaintingLayerForVisualOverflowRecalc();
 
-  void SetShouldDoFullPaintInvalidationWithoutGeometryChangeInternal(
+  void SetShouldDoFullPaintInvalidationWithoutLayoutChangeInternal(
       PaintInvalidationReason);
 
   // Additional bitfields.
@@ -4090,8 +4085,8 @@
           subtree_should_do_full_paint_invalidation_(false),
           may_need_paint_invalidation_animated_background_image_(false),
           should_invalidate_selection_(false),
-          should_check_geometry_for_paint_invalidation_(true),
-          descendant_should_check_geometry_for_paint_invalidation_(true),
+          should_check_layout_for_paint_invalidation_(true),
+          descendant_should_check_layout_for_paint_invalidation_(true),
           needs_paint_property_update_(true),
           descendant_needs_paint_property_update_(true),
           floating_(false),
@@ -4247,11 +4242,10 @@
                          MayNeedPaintInvalidationAnimatedBackgroundImage);
     ADD_BOOLEAN_BITFIELD(should_invalidate_selection_,
                          ShouldInvalidateSelection);
-    ADD_BOOLEAN_BITFIELD(should_check_geometry_for_paint_invalidation_,
-                         ShouldCheckGeometryForPaintInvalidation);
-    ADD_BOOLEAN_BITFIELD(
-        descendant_should_check_geometry_for_paint_invalidation_,
-        DescendantShouldCheckGeometryForPaintInvalidation);
+    ADD_BOOLEAN_BITFIELD(should_check_layout_for_paint_invalidation_,
+                         ShouldCheckLayoutForPaintInvalidation);
+    ADD_BOOLEAN_BITFIELD(descendant_should_check_layout_for_paint_invalidation_,
+                         DescendantShouldCheckLayoutForPaintInvalidation);
     // Whether the paint properties need to be updated. For more details, see
     // LayoutObject::NeedsPaintPropertyUpdate().
     ADD_BOOLEAN_BITFIELD(needs_paint_property_update_,
diff --git a/third_party/blink/renderer/core/layout/layout_object_test.cc b/third_party/blink/renderer/core/layout/layout_object_test.cc
index da12ec05..621296c4 100644
--- a/third_party/blink/renderer/core/layout/layout_object_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_test.cc
@@ -573,7 +573,7 @@
   LayoutObject* object = GetDocument().body()->GetLayoutObject();
   object->SetShouldDoFullPaintInvalidation();
   EXPECT_TRUE(object->ShouldDoFullPaintInvalidation());
-  EXPECT_TRUE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_TRUE(object->ShouldCheckLayoutForPaintInvalidation());
   object->SetShouldCheckForPaintInvalidation();
   EXPECT_TRUE(object->ShouldCheckForPaintInvalidation());
   object->SetSubtreeShouldCheckForPaintInvalidation();
@@ -618,68 +618,73 @@
   EXPECT_FALSE(object->NeedsPaintPropertyUpdate());
 }
 
-TEST_F(LayoutObjectTest, ShouldCheckGeometryForPaintInvalidation) {
+TEST_F(LayoutObjectTest, ShouldCheckLayoutForPaintInvalidation) {
   LayoutObject* object = GetDocument().body()->GetLayoutObject();
   LayoutObject* parent = object->Parent();
 
   object->SetShouldDoFullPaintInvalidation();
   EXPECT_TRUE(object->ShouldDoFullPaintInvalidation());
-  EXPECT_TRUE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_EQ(PaintInvalidationReason::kLayout,
+            object->FullPaintInvalidationReason());
+  EXPECT_TRUE(object->ShouldCheckLayoutForPaintInvalidation());
   EXPECT_TRUE(parent->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(parent->ShouldCheckGeometryForPaintInvalidation());
-  EXPECT_TRUE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(parent->ShouldCheckLayoutForPaintInvalidation());
+  EXPECT_TRUE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
   object->ClearPaintInvalidationFlags();
   EXPECT_FALSE(object->ShouldDoFullPaintInvalidation());
-  EXPECT_FALSE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(object->ShouldCheckLayoutForPaintInvalidation());
   parent->ClearPaintInvalidationFlags();
   EXPECT_FALSE(parent->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(parent->ShouldCheckGeometryForPaintInvalidation());
-  EXPECT_FALSE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(parent->ShouldCheckLayoutForPaintInvalidation());
+  EXPECT_FALSE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
 
   object->SetShouldCheckForPaintInvalidation();
   EXPECT_TRUE(object->ShouldCheckForPaintInvalidation());
-  EXPECT_TRUE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_TRUE(object->ShouldCheckLayoutForPaintInvalidation());
   EXPECT_TRUE(parent->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(parent->ShouldCheckGeometryForPaintInvalidation());
-  EXPECT_TRUE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(parent->ShouldCheckLayoutForPaintInvalidation());
+  EXPECT_TRUE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
   object->ClearPaintInvalidationFlags();
   EXPECT_FALSE(object->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(object->ShouldCheckLayoutForPaintInvalidation());
   parent->ClearPaintInvalidationFlags();
   EXPECT_FALSE(parent->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(parent->ShouldCheckGeometryForPaintInvalidation());
-  EXPECT_FALSE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(parent->ShouldCheckLayoutForPaintInvalidation());
+  EXPECT_FALSE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
 
-  object->SetShouldDoFullPaintInvalidationWithoutGeometryChange();
+  object->SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+      PaintInvalidationReason::kStyle);
+  EXPECT_EQ(PaintInvalidationReason::kStyle,
+            object->FullPaintInvalidationReason());
   EXPECT_TRUE(object->ShouldDoFullPaintInvalidation());
-  EXPECT_FALSE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(object->ShouldCheckLayoutForPaintInvalidation());
   EXPECT_TRUE(parent->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(parent->ShouldCheckGeometryForPaintInvalidation());
-  EXPECT_FALSE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(parent->ShouldCheckLayoutForPaintInvalidation());
+  EXPECT_FALSE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
   object->SetShouldCheckForPaintInvalidation();
-  EXPECT_TRUE(object->ShouldCheckGeometryForPaintInvalidation());
-  EXPECT_TRUE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_TRUE(object->ShouldCheckLayoutForPaintInvalidation());
+  EXPECT_TRUE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
   object->ClearPaintInvalidationFlags();
   EXPECT_FALSE(object->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(object->ShouldCheckLayoutForPaintInvalidation());
   parent->ClearPaintInvalidationFlags();
   EXPECT_FALSE(parent->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
 
-  object->SetShouldCheckForPaintInvalidationWithoutGeometryChange();
+  object->SetShouldCheckForPaintInvalidationWithoutLayoutChange();
   EXPECT_TRUE(object->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(object->ShouldCheckLayoutForPaintInvalidation());
   EXPECT_TRUE(parent->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
   object->SetShouldCheckForPaintInvalidation();
-  EXPECT_TRUE(object->ShouldCheckGeometryForPaintInvalidation());
-  EXPECT_TRUE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_TRUE(object->ShouldCheckLayoutForPaintInvalidation());
+  EXPECT_TRUE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
   object->ClearPaintInvalidationFlags();
   EXPECT_FALSE(object->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(object->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(object->ShouldCheckLayoutForPaintInvalidation());
   parent->ClearPaintInvalidationFlags();
   EXPECT_FALSE(parent->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(parent->DescendantShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(parent->DescendantShouldCheckLayoutForPaintInvalidation());
 }
 
 TEST_F(LayoutObjectTest, AssociatedLayoutObjectOfFirstLetterPunctuations) {
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.cc b/third_party/blink/renderer/core/layout/layout_table_cell.cc
index 95f47b2..6dfbfa6d 100644
--- a/third_party/blink/renderer/core/layout/layout_table_cell.cc
+++ b/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -1157,7 +1157,7 @@
   auto row_span = ResolvedRowSpan();
   for (auto r = RowIndex(); r < RowIndex() + row_span; ++r) {
     if (auto* row = Section()->RowLayoutObjectAt(r))
-      row->SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kStyle);
+      row->SetShouldDoFullPaintInvalidation();
   }
   collapsed_borders_need_paint_invalidation_ = false;
 }
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
index 8fda25d3..9feadd71 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
@@ -180,9 +180,9 @@
     const PaintInvalidatorContext& context) const {
   // Fieldset's box decoration painting depends on the legend geometry.
   const LayoutBox* legend_box = LayoutFieldset::FindInFlowLegend(*this);
-  if (legend_box && legend_box->ShouldCheckGeometryForPaintInvalidation()) {
+  if (legend_box && legend_box->ShouldCheckLayoutForPaintInvalidation()) {
     GetMutableForPainting().SetShouldDoFullPaintInvalidation(
-        PaintInvalidationReason::kGeometry);
+        PaintInvalidationReason::kLayout);
   }
   LayoutNGBlockFlow::InvalidatePaint(context);
 }
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
index 692f422..b0c3875 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table.cc
@@ -86,7 +86,7 @@
   NOT_DESTROYED();
   InvalidateCachedTableBorders();
   if (StyleRef().BorderCollapse() == EBorderCollapse::kCollapse) {
-    SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+    SetShouldDoFullPaintInvalidationWithoutLayoutChange(
         PaintInvalidationReason::kStyle);
     // If borders change, table fragment must be regenerated.
     SetNeedsLayoutAndIntrinsicWidthsRecalc(
@@ -99,7 +99,7 @@
   // Callers must ensure table layout gets invalidated.
   InvalidateCachedTableBorders();
   if (StyleRef().BorderCollapse() == EBorderCollapse::kCollapse)
-    SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kStyle);
+    SetShouldDoFullPaintInvalidation();
 }
 
 bool LayoutNGTable::HasBackgroundForPaint() const {
diff --git a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
index 3c6d6ef..8db3a4c 100644
--- a/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.cc
@@ -55,7 +55,7 @@
 void LayoutNGTableColumn::ImageChanged(WrappedImagePtr, CanDeferInvalidation) {
   NOT_DESTROYED();
   if (LayoutNGTable* table = Table()) {
-    table->SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+    table->SetShouldDoFullPaintInvalidationWithoutLayoutChange(
         PaintInvalidationReason::kImage);
   }
 }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
index e2e2fffc..8fa0dc4 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
@@ -166,7 +166,7 @@
 
   const bool bbox_changed = UpdateBoundingBox();
   if (bbox_changed) {
-    SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kImage);
+    SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kSVGResource);
 
     // Invalidate all resources of this client if our reference box changed.
     if (EverHadLayout())
@@ -252,7 +252,8 @@
   if (CalculateObjectSize() != object_bounding_box_.size())
     SetNeedsLayout(layout_invalidation_reason::kSizeChanged);
 
-  SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kImage);
+  SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+      PaintInvalidationReason::kImage);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index 139b641..cd037ebc 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -376,7 +376,7 @@
   const AffineTransform transform = ComputeNonScalingStrokeTransform();
   auto& rare_data = EnsureRareData();
   if (rare_data.non_scaling_stroke_transform_ != transform) {
-    SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kStyle);
+    SetShouldDoFullPaintInvalidation();
     rare_data.non_scaling_stroke_transform_ = transform;
   }
 
diff --git a/third_party/blink/renderer/core/page/print_context_test.cc b/third_party/blink/renderer/core/page/print_context_test.cc
index 95835b3f..aada5f7e 100644
--- a/third_party/blink/renderer/core/page/print_context_test.cc
+++ b/third_party/blink/renderer/core/page/print_context_test.cc
@@ -130,14 +130,17 @@
     GetDocument().body()->setInnerHTML(body_content);
   }
 
-  void PrintSinglePage(SkCanvas& canvas) {
-    gfx::Rect page_rect(0, 0, kPageWidth, kPageHeight);
+  gfx::Rect PrintSinglePage(SkCanvas& canvas, int page_number = 0) {
     GetDocument().SetPrinting(Document::kBeforePrinting);
     Event* event = MakeGarbageCollected<BeforePrintEvent>();
     GetPrintContext().GetFrame()->DomWindow()->DispatchEvent(*event);
-    GetPrintContext().BeginPrintMode(page_rect.width(), page_rect.height());
+    GetPrintContext().BeginPrintMode(kPageWidth, kPageHeight);
     GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
         DocumentUpdateReason::kTest);
+
+    GetPrintContext().ComputePageRects(gfx::SizeF(kPageWidth, kPageHeight));
+    gfx::Rect page_rect = GetPrintContext().PageRect(page_number);
+
     auto* builder = MakeGarbageCollected<PaintRecordBuilder>();
     GraphicsContext& context = builder->Context();
     context.SetPrinting(true);
@@ -151,6 +154,7 @@
     }
     builder->EndRecording()->Playback(&canvas);
     GetPrintContext().EndPrintMode();
+    return page_rect;
   }
 
   static String AbsoluteBlockHtmlForLink(int x,
@@ -466,6 +470,57 @@
   EXPECT_SKRECT_EQ(50, 60, 200, 100, operations[0].rect);
 }
 
+TEST_P(PrintContextTest, LinkInFragmentedContainer) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      body {
+        margin: 0;
+        line-height: 50px;
+        orphans: 1;
+        widows: 1;
+      }
+    </style>
+    <div style="height:calc(100vh - 90px);"></div>
+    <div>
+      <a href="http://www.google.com">link 1</a><br>
+      <!-- Page break here. -->
+      <a href="http://www.google.com">link 2</a><br>
+      <a href="http://www.google.com">link 3</a><br>
+    </div>
+  )HTML");
+
+  MockPageContextCanvas first_page_canvas;
+  gfx::Rect page_rect = PrintSinglePage(first_page_canvas, 0);
+  Vector<MockPageContextCanvas::Operation> operations =
+      first_page_canvas.RecordedOperations();
+
+  // TODO(crbug.com/1392701): Should be 1.
+  ASSERT_EQ(operations.size(), 3u);
+
+  const auto& page1_link1 = operations[0];
+  EXPECT_EQ(page1_link1.type, MockPageContextCanvas::kDrawRect);
+  EXPECT_GE(page1_link1.rect.y(), page_rect.height() - 90);
+  EXPECT_LE(page1_link1.rect.bottom(), page_rect.height() - 40);
+
+  MockPageContextCanvas second_page_canvas;
+  page_rect = PrintSinglePage(second_page_canvas, 1);
+  operations = second_page_canvas.RecordedOperations();
+
+  // TODO(crbug.com/1392701): Should be 2.
+  ASSERT_EQ(operations.size(), 3u);
+  // TODO(crbug.com/1392701): Should be operations[0]
+  const auto& page2_link1 = operations[1];
+  // TODO(crbug.com/1392701): Should be operations[1]
+  const auto& page2_link2 = operations[2];
+
+  EXPECT_EQ(page2_link1.type, MockPageContextCanvas::kDrawRect);
+  EXPECT_GE(page2_link1.rect.y(), page_rect.y());
+  EXPECT_LE(page2_link1.rect.bottom(), page_rect.y() + 50);
+  EXPECT_EQ(page2_link2.type, MockPageContextCanvas::kDrawRect);
+  EXPECT_GE(page2_link2.rect.y(), page_rect.y() + 50);
+  EXPECT_LE(page2_link2.rect.bottom(), page_rect.y() + 100);
+}
+
 // Here are a few tests to check that shrink to fit doesn't mess up page count.
 
 TEST_P(PrintContextTest, ScaledVerticalRL1) {
diff --git a/third_party/blink/renderer/core/paint/box_paint_invalidator.cc b/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
index 7bd7c6c..cca3852 100644
--- a/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
@@ -121,14 +121,22 @@
       ObjectPaintInvalidatorWithContext(box_, context_)
           .ComputePaintInvalidationReason();
 
-  if (reason != PaintInvalidationReason::kIncremental)
+  if (reason == PaintInvalidationReason::kNone)
     return reason;
 
+  if (IsLayoutPaintInvalidationReason(reason))
+    return reason;
+
+  if (IsFullPaintInvalidationReason(reason) &&
+      !box_.ShouldCheckLayoutForPaintInvalidation()) {
+    return reason;
+  }
+
   const ComputedStyle& style = box_.StyleRef();
 
   if (style.MaskLayers().AnyLayerUsesContentBox() &&
       box_.PreviousPhysicalContentBoxRect() != box_.PhysicalContentBoxRect())
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
 
 #if DCHECK_IS_ON()
   // TODO(crbug.com/1205708): Audit this.
@@ -136,15 +144,18 @@
 #endif
   if (box_.PreviousSize() == box_.Size() &&
       box_.PreviousPhysicalSelfVisualOverflowRect() ==
-          box_.PhysicalSelfVisualOverflowRect())
-    return PaintInvalidationReason::kNone;
+          box_.PhysicalSelfVisualOverflowRect()) {
+    return IsFullPaintInvalidationReason(reason)
+               ? reason
+               : PaintInvalidationReason::kNone;
+  }
 
   // Incremental invalidation is not applicable if there is visual overflow.
   if (box_.PreviousPhysicalSelfVisualOverflowRect().size !=
           PhysicalSizeToBeNoop(box_.PreviousSize()) ||
       box_.PhysicalSelfVisualOverflowRect().size !=
           PhysicalSizeToBeNoop(box_.Size()))
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
 
   // Incremental invalidation is not applicable if paint offset or size has
   // fraction.
@@ -152,34 +163,34 @@
       context_.fragment_data->PaintOffset().HasFraction() ||
       PhysicalSizeToBeNoop(box_.PreviousSize()).HasFraction() ||
       PhysicalSizeToBeNoop(box_.Size()).HasFraction())
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
 
   // Incremental invalidation is not applicable if there is border in the
   // direction of border box size change because we don't know the border
   // width when issuing incremental raster invalidations.
   if (box_.BorderRight() || box_.BorderBottom())
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
 
   if (style.HasVisualOverflowingEffect() || style.HasEffectiveAppearance() ||
       style.HasFilterInducingProperty() || style.HasMask() ||
       style.HasClipPath())
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
 
   if (style.HasBorderRadius() || style.CanRenderBorderImage())
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
 
   // Needs to repaint frame boundaries.
   if (box_.IsFrameSetIncludingNG())
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
 
   // Needs to repaint column rules.
   if (box_.IsLayoutMultiColumnSet())
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
 
   // Background invalidation has been done during InvalidateBackground(), so
   // we don't need to check background in this function.
 
-  return PaintInvalidationReason::kIncremental;
+  return reason;
 }
 
 bool BoxPaintInvalidator::BackgroundGeometryDependsOnLayoutOverflowRect() {
@@ -362,7 +373,7 @@
       (BackgroundPaintsInBorderBoxSpace() &&
        background_invalidation_type == BackgroundInvalidationType::kFull)) {
     box_.GetMutableForPainting()
-        .SetShouldDoFullPaintInvalidationWithoutGeometryChange(
+        .SetShouldDoFullPaintInvalidationWithoutLayoutChange(
             PaintInvalidationReason::kBackground);
   }
 }
diff --git a/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc b/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
index 2e38c45896..f3680a10 100644
--- a/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
+++ b/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
@@ -57,7 +57,7 @@
     GetDocument().View()->UpdateLifecycleToLayoutClean(
         DocumentUpdateReason::kTest);
 
-    EXPECT_EQ(PaintInvalidationReason::kGeometry,
+    EXPECT_EQ(PaintInvalidationReason::kLayout,
               ComputePaintInvalidationReason(box, paint_offset));
   }
 
@@ -114,7 +114,7 @@
 
   // Paint offset change.
   auto old_paint_offset = paint_offset + PhysicalOffset(10, 20);
-  EXPECT_EQ(PaintInvalidationReason::kGeometry,
+  EXPECT_EQ(PaintInvalidationReason::kLayout,
             ComputePaintInvalidationReason(box, old_paint_offset));
 
   // Size change.
@@ -160,15 +160,20 @@
   GetDocument().View()->UpdateLifecycleToLayoutClean(
       DocumentUpdateReason::kTest);
 
-  EXPECT_EQ(PaintInvalidationReason::kGeometry,
+  EXPECT_EQ(PaintInvalidationReason::kLayout,
             ComputePaintInvalidationReason(box, paint_offset));
 
-  // Should use the existing full paint invalidation reason regardless of
-  // geometry change.
-  box.SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kStyle);
-  EXPECT_EQ(PaintInvalidationReason::kStyle,
+  // Computed kLayout has higher priority than the non-geometry paint
+  // invalidation reason on the LayoutBox.
+  box.SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+      PaintInvalidationReason::kStyle);
+  EXPECT_EQ(PaintInvalidationReason::kLayout,
             ComputePaintInvalidationReason(box, paint_offset));
-  EXPECT_EQ(PaintInvalidationReason::kStyle,
+
+  // If the LayoutBox has a geometry paint invalidation reason, the reason is
+  // returned directly without checking geometry change.
+  box.SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kSVGResource);
+  EXPECT_EQ(PaintInvalidationReason::kSVGResource,
             ComputePaintInvalidationReason(box, paint_offset));
 }
 
@@ -230,7 +235,7 @@
   EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
               UnorderedElementsAre(RasterInvalidationInfo{
                   object->Id(), object->DebugName(), gfx::Rect(0, 0, 72, 142),
-                  PaintInvalidationReason::kStyle}));
+                  PaintInvalidationReason::kLayout}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 
   GetDocument().View()->SetTracksRasterInvalidations(true);
@@ -240,7 +245,7 @@
   EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
               UnorderedElementsAre(RasterInvalidationInfo{
                   object->Id(), object->DebugName(), gfx::Rect(0, 0, 122, 142),
-                  PaintInvalidationReason::kGeometry}));
+                  PaintInvalidationReason::kLayout}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
 
diff --git a/third_party/blink/renderer/core/paint/find_paint_offset_needing_update.h b/third_party/blink/renderer/core/paint/find_paint_offset_needing_update.h
index 4690f66..807c284c 100644
--- a/third_party/blink/renderer/core/paint/find_paint_offset_needing_update.h
+++ b/third_party/blink/renderer/core/paint/find_paint_offset_needing_update.h
@@ -21,7 +21,7 @@
 // FindPaintOffsetNeedingUpdateScope catches cases where paint offset needed
 // an update but was not marked as such. If paint offset will change, the
 // object must be marked as such by
-// LayoutObject::SetShouldCheckGeometryForPaintInvalidation()
+// LayoutObject::SetShouldCheckLayoutForPaintInvalidation()
 // (which is a private function called by several public paint-invalidation-flag
 // setting functions).
 class FindPaintOffsetNeedingUpdateScope {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 7f632827..48cb8b5 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -821,8 +821,20 @@
 
   if (child_paint_info.phase == PaintPhase::kForeground &&
       child_paint_info.ShouldAddUrlMetadata()) {
+    // TODO(crbug.com/1392701): Avoid walking the LayoutObject tree (which is
+    // what AddURLRectsForInlineChildrenRecursively() does). We should walk the
+    // fragment tree instead (if we can figure out how to deal with culled
+    // inlines - or get rid of them). Walking the LayoutObject tree means that
+    // we'll visit every link in the container for each fragment generated,
+    // leading to duplicate entries. This is only fine as long as the absolute
+    // offsets is the same every time a given link is visited. Otherwise links
+    // might end up as unclickable in the resulting PDF. So make sure that the
+    // paint offset relative to the first fragment generated by this
+    // container. This matches legacy engine behavior.
+    PhysicalOffset paint_offset_for_first_fragment =
+        paint_offset - OffsetInStitchedFragments(box_fragment_);
     AddURLRectsForInlineChildrenRecursively(*layout_object, child_paint_info,
-                                            paint_offset);
+                                            paint_offset_for_first_fragment);
   }
 
   // If we have no lines then we have no work to do.
diff --git a/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.cc b/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.cc
index a5851d8..f6e59b3 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.cc
@@ -274,8 +274,10 @@
   PhysicalOffset offset = line_item.OffsetInContainerFragment();
   const NGPhysicalLineBoxFragment* fragment = line_item.LineBoxFragment();
   DCHECK(fragment);
-  offset.top += fragment->Metrics().ascent;
-  offset.top -= style.GetFont().PrimaryFont()->GetFontMetrics().FixedAscent();
+  if (const SimpleFontData* font = style.GetFont().PrimaryFont()) {
+    offset.top += fragment->Metrics().ascent;
+    offset.top -= font->GetFontMetrics().FixedAscent();
+  }
 
   // If the block has multiple decorations, all decorations have the same
   // decorating box, which is a non-existent anonymous inline box that wraps all
diff --git a/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.cc b/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.cc
index ac9007c1..f40c78a5 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_table_cell_paint_invalidator.cc
@@ -28,7 +28,7 @@
   // so we should invalidate the container immediately here instead of setting
   // paint invalidation flags.
   container_context.painting_layer->SetNeedsRepaint();
-  container.InvalidateDisplayItemClients(PaintInvalidationReason::kGeometry);
+  container.InvalidateDisplayItemClients(PaintInvalidationReason::kLayout);
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/paint/object_paint_invalidator.cc b/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
index 333eebe1..a85f271 100644
--- a/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
@@ -42,15 +42,15 @@
     return PaintInvalidationReason::kNone;
   }
 
-  if (object_.ShouldDoFullPaintInvalidation())
-    return object_.FullPaintInvalidationReason();
-
   if (context_.subtree_flags &
       PaintInvalidatorContext::kSubtreeFullInvalidation)
     return PaintInvalidationReason::kSubtree;
 
   if (context_.fragment_data->PaintOffset() != context_.old_paint_offset)
-    return PaintInvalidationReason::kGeometry;
+    return PaintInvalidationReason::kLayout;
+
+  if (object_.ShouldDoFullPaintInvalidation())
+    return object_.FullPaintInvalidationReason();
 
   if (object_.GetDocument().InForcedColorsMode() && object_.IsLayoutBlockFlow())
     return PaintInvalidationReason::kBackplate;
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 1c822f40..614d3c3 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
@@ -207,10 +207,10 @@
               UnorderedElementsAre(
                   RasterInvalidationInfo{object->Id(), object->DebugName(),
                                          gfx::Rect(0, 0, 50, 100),
-                                         PaintInvalidationReason::kGeometry},
+                                         PaintInvalidationReason::kLayout},
                   RasterInvalidationInfo{object->Id(), object->DebugName(),
                                          gfx::Rect(0, 0, 101, 70),
-                                         PaintInvalidationReason::kGeometry}));
+                                         PaintInvalidationReason::kLayout}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 
   GetDocument().View()->SetTracksRasterInvalidations(true);
@@ -220,10 +220,10 @@
               UnorderedElementsAre(
                   RasterInvalidationInfo{object->Id(), object->DebugName(),
                                          gfx::Rect(0, 0, 50, 100),
-                                         PaintInvalidationReason::kGeometry},
+                                         PaintInvalidationReason::kLayout},
                   RasterInvalidationInfo{object->Id(), object->DebugName(),
                                          gfx::Rect(0, 0, 101, 70),
-                                         PaintInvalidationReason::kGeometry}));
+                                         PaintInvalidationReason::kLayout}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
 
@@ -242,10 +242,10 @@
               UnorderedElementsAre(
                   RasterInvalidationInfo{object->Id(), object->DebugName(),
                                          gfx::Rect(0, 0, 100, 200),
-                                         PaintInvalidationReason::kGeometry},
+                                         PaintInvalidationReason::kLayout},
                   RasterInvalidationInfo{object->Id(), object->DebugName(),
                                          gfx::Rect(0, 0, 202, 140),
-                                         PaintInvalidationReason::kGeometry}));
+                                         PaintInvalidationReason::kLayout}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 
   GetDocument().View()->SetTracksRasterInvalidations(true);
@@ -255,10 +255,10 @@
               UnorderedElementsAre(
                   RasterInvalidationInfo{object->Id(), object->DebugName(),
                                          gfx::Rect(0, 0, 100, 200),
-                                         PaintInvalidationReason::kGeometry},
+                                         PaintInvalidationReason::kLayout},
                   RasterInvalidationInfo{object->Id(), object->DebugName(),
                                          gfx::Rect(0, 0, 202, 140),
-                                         PaintInvalidationReason::kGeometry}));
+                                         PaintInvalidationReason::kLayout}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
 
@@ -274,7 +274,7 @@
   EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
               UnorderedElementsAre(RasterInvalidationInfo{
                   object->Id(), object->DebugName(), gfx::Rect(0, 0, 50, 100),
-                  PaintInvalidationReason::kGeometry}));
+                  PaintInvalidationReason::kLayout}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 
   GetDocument().View()->SetTracksRasterInvalidations(true);
@@ -284,7 +284,7 @@
   EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
               UnorderedElementsAre(RasterInvalidationInfo{
                   object->Id(), object->DebugName(), gfx::Rect(0, 1, 50, 99),
-                  PaintInvalidationReason::kGeometry}));
+                  PaintInvalidationReason::kLayout}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
 
@@ -565,11 +565,10 @@
   target->setAttribute(html_names::kStyleAttr, "height: 200px");
   UpdateAllLifecyclePhasesForTest();
   // Border invalidated in the container layer.
-  EXPECT_THAT(
-      container_raster_invalidation_tracking()->Invalidations(),
-      UnorderedElementsAre(RasterInvalidationInfo{
-          target_obj->Id(), target_obj->DebugName(), gfx::Rect(0, 0, 70, 220),
-          PaintInvalidationReason::kGeometry}));
+  EXPECT_THAT(container_raster_invalidation_tracking()->Invalidations(),
+              UnorderedElementsAre(RasterInvalidationInfo{
+                  target_obj->Id(), target_obj->DebugName(),
+                  gfx::Rect(0, 0, 70, 220), PaintInvalidationReason::kLayout}));
   // No invalidation on scrolling contents for container resize.
   EXPECT_FALSE(contents_raster_invalidation_tracking()->HasInvalidations());
   GetDocument().View()->SetTracksRasterInvalidations(false);
@@ -621,11 +620,10 @@
   target->setAttribute(html_names::kStyleAttr, "height: 200px");
   UpdateAllLifecyclePhasesForTest();
   // Border invalidated in the container layer.
-  EXPECT_THAT(
-      container_raster_invalidation_tracking()->Invalidations(),
-      UnorderedElementsAre(RasterInvalidationInfo{
-          target_obj->Id(), target_obj->DebugName(), gfx::Rect(0, 0, 70, 220),
-          PaintInvalidationReason::kGeometry}));
+  EXPECT_THAT(container_raster_invalidation_tracking()->Invalidations(),
+              UnorderedElementsAre(RasterInvalidationInfo{
+                  target_obj->Id(), target_obj->DebugName(),
+                  gfx::Rect(0, 0, 70, 220), PaintInvalidationReason::kLayout}));
   // No invalidation on scrolling contents for container resize.
   EXPECT_FALSE(contents_raster_invalidation_tracking()->HasInvalidations());
   GetDocument().View()->SetTracksRasterInvalidations(false);
@@ -753,14 +751,14 @@
   )HTML");
 
   auto* target = GetLayoutObjectByElementId("target");
-  target->SetShouldDoFullPaintInvalidationWithoutGeometryChange(
-      PaintInvalidationReason::kForTesting);
+  target->SetShouldDoFullPaintInvalidationWithoutLayoutChange(
+      PaintInvalidationReason::kStyle);
   target->SetShouldDelayFullPaintInvalidation();
   EXPECT_FALSE(target->ShouldDoFullPaintInvalidation());
   EXPECT_TRUE(target->ShouldDelayFullPaintInvalidation());
-  EXPECT_EQ(PaintInvalidationReason::kForTesting,
+  EXPECT_EQ(PaintInvalidationReason::kStyle,
             target->FullPaintInvalidationReason());
-  EXPECT_FALSE(target->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(target->ShouldCheckLayoutForPaintInvalidation());
   EXPECT_TRUE(target->ShouldCheckForPaintInvalidation());
   EXPECT_TRUE(target->Parent()->ShouldCheckForPaintInvalidation());
 
@@ -769,9 +767,9 @@
   EXPECT_FALSE(GetRasterInvalidationTracking()->HasInvalidations());
   EXPECT_FALSE(target->ShouldDoFullPaintInvalidation());
   EXPECT_TRUE(target->ShouldDelayFullPaintInvalidation());
-  EXPECT_EQ(PaintInvalidationReason::kForTesting,
+  EXPECT_EQ(PaintInvalidationReason::kStyle,
             target->FullPaintInvalidationReason());
-  EXPECT_FALSE(target->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(target->ShouldCheckLayoutForPaintInvalidation());
   EXPECT_TRUE(target->ShouldCheckForPaintInvalidation());
   EXPECT_TRUE(target->Parent()->ShouldCheckForPaintInvalidation());
   GetDocument().View()->SetTracksRasterInvalidations(false);
@@ -784,13 +782,13 @@
       GetRasterInvalidationTracking()->Invalidations(),
       UnorderedElementsAre(RasterInvalidationInfo{
           target->Id(), target->DebugName(), gfx::Rect(0, 4000, 100, 100),
-          PaintInvalidationReason::kForTesting}));
+          PaintInvalidationReason::kStyle}));
   EXPECT_EQ(PaintInvalidationReason::kNone,
             target->FullPaintInvalidationReason());
   EXPECT_FALSE(target->ShouldDelayFullPaintInvalidation());
   EXPECT_FALSE(target->ShouldCheckForPaintInvalidation());
   EXPECT_FALSE(target->Parent()->ShouldCheckForPaintInvalidation());
-  EXPECT_FALSE(target->ShouldCheckGeometryForPaintInvalidation());
+  EXPECT_FALSE(target->ShouldCheckLayoutForPaintInvalidation());
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
 
@@ -1021,10 +1019,10 @@
                                   ->GetScrollCornerDisplayItemClient();
   invalidations.push_back(RasterInvalidationInfo{
       scroll_corner.Id(), scroll_corner.DebugName(), gfx::Rect(93, 93, 7, 7),
-      PaintInvalidationReason::kGeometry});
+      PaintInvalidationReason::kLayout});
   invalidations.push_back(RasterInvalidationInfo{
       scroll_corner.Id(), scroll_corner.DebugName(), gfx::Rect(193, 93, 7, 7),
-      PaintInvalidationReason::kGeometry});
+      PaintInvalidationReason::kLayout});
   EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
               UnorderedElementsAreArray(invalidations));
 
diff --git a/third_party/blink/renderer/core/paint/paint_invalidator.cc b/third_party/blink/renderer/core/paint/paint_invalidator.cc
index 8bd4b01..cc8f00e 100644
--- a/third_party/blink/renderer/core/paint/paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -90,7 +90,7 @@
     const LayoutObject& object,
     const PaintPropertyTreeBuilderFragmentContext& tree_builder_context,
     PaintInvalidatorContext& context) {
-  if (!object.ShouldCheckGeometryForPaintInvalidation())
+  if (!object.ShouldCheckLayoutForPaintInvalidation())
     return;
 
   if (tree_builder_context.this_or_ancestor_opacity_is_zero ||
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 6f55168..1a2795f3 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -2950,7 +2950,7 @@
     context.painting_layer->SetNeedsRepaint();
     const auto& box = *GetLayoutBox();
     ObjectPaintInvalidator(box).InvalidateDisplayItemClient(
-        box, PaintInvalidationReason::kGeometry);
+        box, PaintInvalidationReason::kLayout);
   }
 
   previously_was_overlay = is_overlay;
@@ -3022,7 +3022,7 @@
     context.painting_layer->SetNeedsRepaint();
     ObjectPaintInvalidator(*GetLayoutBox())
         .InvalidateDisplayItemClient(GetScrollCornerDisplayItemClient(),
-                                     PaintInvalidationReason::kGeometry);
+                                     PaintInvalidationReason::kLayout);
   }
 
   ClearNeedsPaintInvalidationForScrollControls();
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index 8a5dc749..3e9c87e9 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -298,10 +298,10 @@
 bool PrePaintTreeWalk::ObjectRequiresTreeBuilderContext(
     const LayoutObject& object) {
   return object.NeedsPaintPropertyUpdate() ||
-         object.ShouldCheckGeometryForPaintInvalidation() ||
+         object.ShouldCheckLayoutForPaintInvalidation() ||
          (!object.ChildPrePaintBlockedByDisplayLock() &&
           (object.DescendantNeedsPaintPropertyUpdate() ||
-           object.DescendantShouldCheckGeometryForPaintInvalidation()));
+           object.DescendantShouldCheckLayoutForPaintInvalidation()));
 }
 
 bool PrePaintTreeWalk::ContextRequiresChildTreeBuilderContext(
@@ -329,8 +329,8 @@
 
   DCHECK(!object.NeedsPaintPropertyUpdate());
   DCHECK(!object.DescendantNeedsPaintPropertyUpdate());
-  DCHECK(!object.DescendantShouldCheckGeometryForPaintInvalidation());
-  DCHECK(!object.ShouldCheckGeometryForPaintInvalidation());
+  DCHECK(!object.DescendantShouldCheckLayoutForPaintInvalidation());
+  DCHECK(!object.ShouldCheckLayoutForPaintInvalidation());
   NOTREACHED() << "Unknown reason.";
 }
 #endif
diff --git a/third_party/blink/renderer/core/paint/table_cell_paint_invalidator.cc b/third_party/blink/renderer/core/paint/table_cell_paint_invalidator.cc
index 2814f390..6fdc40b 100644
--- a/third_party/blink/renderer/core/paint/table_cell_paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/table_cell_paint_invalidator.cc
@@ -31,7 +31,7 @@
   // so we should invalidate the container immediately here instead of setting
   // paint invalidation flags.
   container_context.painting_layer->SetNeedsRepaint();
-  container.InvalidateDisplayItemClients(PaintInvalidationReason::kGeometry);
+  container.InvalidateDisplayItemClients(PaintInvalidationReason::kLayout);
 }
 
 void TableCellPaintInvalidator::InvalidatePaint() {
diff --git a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
index a496cb8..63c004f8 100644
--- a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
+++ b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
@@ -222,7 +222,7 @@
 
   inner_view->SetNeedsLayout("test");
   inner_view->SetShouldDoFullPaintInvalidation(
-      PaintInvalidationReason::kForTesting);
+      PaintInvalidationReason::kLayout);
   inner_view->Layer()->SetNeedsRepaint();
   EXPECT_TRUE(inner_frame_document->View()
                   ->GetLayoutView()
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index 3aa4c77e..28316342c4 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -583,6 +583,15 @@
   return SVGElement::IsPresentationAttribute(attr_name);
 }
 
+void SVGSMILElement::CollectStyleForPresentationAttribute(
+    const QualifiedName& attr_name,
+    const AtomicString& value,
+    MutableCSSPropertyValueSet* style) {
+  if (attr_name == svg_names::kFillAttr)
+    return;
+  SVGElement::CollectStyleForPresentationAttribute(attr_name, value, style);
+}
+
 void SVGSMILElement::ConnectConditions() {
   if (conditions_connected_)
     DisconnectConditions();
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
index ba0520ba..befe7fa 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
@@ -167,6 +167,10 @@
 
  private:
   bool IsPresentationAttribute(const QualifiedName&) const override;
+  void CollectStyleForPresentationAttribute(
+      const QualifiedName&,
+      const AtomicString&,
+      MutableCSSPropertyValueSet*) override;
 
   void AddedEventListener(const AtomicString& event_type,
                           RegisteredEventListener&) final;
diff --git a/third_party/blink/renderer/core/svg/svg_element.cc b/third_party/blink/renderer/core/svg/svg_element.cc
index 1cf9290..e96bcef 100644
--- a/third_party/blink/renderer/core/svg/svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_element.cc
@@ -973,19 +973,19 @@
   if (params.name == html_names::kStyleAttr)
     return;
 
+  CSSPropertyID prop_id =
+      CssPropertyIdForSVGAttributeName(GetExecutionContext(), params.name);
+  if (prop_id > CSSPropertyID::kInvalid) {
+    InvalidateInstances();
+    return;
+  }
+
   SvgAttributeChanged({params.name, params.reason});
   UpdateWebAnimatedAttributeOnBaseValChange(params.name);
 }
 
 void SVGElement::SvgAttributeChanged(const SvgAttributeChangedParams& params) {
   const QualifiedName& attr_name = params.name;
-  CSSPropertyID prop_id = SVGElement::CssPropertyIdForSVGAttributeName(
-      GetExecutionContext(), attr_name);
-  if (prop_id > CSSPropertyID::kInvalid) {
-    InvalidateInstances();
-    return;
-  }
-
   if (attr_name == html_names::kClassAttr) {
     ClassAttributeChanged(AtomicString(class_name_->CurrentValue()->Value()));
     InvalidateInstances();
diff --git a/third_party/blink/renderer/core/svg/svg_element.h b/third_party/blink/renderer/core/svg/svg_element.h
index ad50b62c..4f27437 100644
--- a/third_party/blink/renderer/core/svg/svg_element.h
+++ b/third_party/blink/renderer/core/svg/svg_element.h
@@ -176,6 +176,7 @@
   MutableCSSPropertyValueSet* AnimatedSMILStyleProperties() const;
   MutableCSSPropertyValueSet* EnsureAnimatedSMILStyleProperties();
 
+  virtual void BuildPendingResource() {}
   virtual bool HaveLoadedRequiredResources();
 
   void InvalidateRelativeLengthClients(SubtreeLayoutScope* = nullptr);
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
index f457d7dd..d234fa58 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -149,7 +149,7 @@
 void SoftNavigationHeuristics::ModifiedDOM(ScriptState* script_state) {
   bool descendant =
       SetFlagIfDescendantAndCheck(script_state, FlagType::kMainModification);
-  TRACE_EVENT1("scheduler", "SoftNavigationHeuristics::ModifiedMain",
+  TRACE_EVENT1("scheduler", "SoftNavigationHeuristics::ModifiedDOM",
                "descendant", descendant);
   SetIsTrackingSoftNavigationHeuristicsOnDocument(false);
 }
@@ -198,7 +198,7 @@
 
   ResetHeuristic();
   LogToConsole(frame, mojom::blink::ConsoleMessageLevel::kInfo,
-               String("A soft navigation has been detected."));
+               String("A soft navigation has been detected: ") + url_);
   TRACE_EVENT0("scheduler",
                "SoftNavigationHeuristics soft navigation detected");
   if (LocalFrameClient* frame_client = frame->Client()) {
diff --git a/third_party/blink/renderer/core/view_transition/view_transition.cc b/third_party/blink/renderer/core/view_transition/view_transition.cc
index 1d0db2a..8cce4b5 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition.cc
@@ -626,6 +626,10 @@
       case State::kAnimating: {
         if (first_animating_frame_) {
           first_animating_frame_ = false;
+          // We need to schedule an animation frame, in case this is the only
+          // kAnimating frame we will get, so that we can clean up in the next
+          // frame.
+          document_->View()->ScheduleAnimation();
           break;
         }
 
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_style_builder.cc b/third_party/blink/renderer/core/view_transition/view_transition_style_builder.cc
index 2d06d2e..6920a2c 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_style_builder.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_style_builder.cc
@@ -62,8 +62,6 @@
   rule_builder.Append("animation-name: ");
   rule_builder.Append(animation_name);
   rule_builder.Append(";\n");
-  rule_builder.Append("animation-duration: 0.25s;\n");
-  rule_builder.Append("animation-fill-mode: both;\n");
   rule_builder.Append("animation-timing-function: ease;\n");
   rule_builder.Append("animation-delay: 0s;\n");
   rule_builder.Append("animation-iteration-count: 1;\n");
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc
index babd3f5..ccb225a 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/core/view_transition/view_transition_utils.h"
 #include "third_party/blink/renderer/platform/data_resource_helper.h"
 #include "third_party/blink/renderer/platform/geometry/layout_size.h"
+#include "third_party/blink/renderer/platform/widget/frame_widget.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
@@ -1040,9 +1041,11 @@
       top += controls.TopHeight() - controls.TopMinHeight();
     if (controls.BottomShownRatio())
       bottom += controls.BottomHeight() - controls.BottomMinHeight();
-  }
 
-  // TODO(bokan): Account for virtual-keyboard
+    bottom += document.GetFrame()
+                  ->GetWidgetForLocalRoot()
+                  ->GetVirtualKeyboardResizeHeight();
+  }
 
   // A left-side scrollbar (i.e. in an RTL writing-mode) should overlay the
   // snapshot viewport as well. This cannot currently happen in Chrome but it
diff --git a/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc b/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
index 6e7faad..7efd7ea6f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.cc
@@ -168,8 +168,8 @@
   AXObjectCacheImpl& cache = AXObjectCache();
   AXObject* descendant = ActiveDescendant();
   cache.PostNotification(this, ax::mojom::Event::kHide);
-  if (descendant)
-    cache.PostNotification(this, ax::mojom::Event::kChildrenChanged);
+  if (descendant)  // TODO(accessibility) Try removing. Line below is enough.
+    cache.MarkAXObjectDirtyWithCleanLayout(this);
   cache.MarkAXSubtreeDirtyWithCleanLayout(ParentObject());
 }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 611b8c2..277e2844b 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -4737,8 +4737,7 @@
   DCHECK(!IsDetached()) << "None of the above should be able to detach |this|: "
                         << ToString(true, true);
 
-  AXObjectCache().PostNotification(this,
-                                   ax::mojom::blink::Event::kChildrenChanged);
+  AXObjectCache().MarkAXObjectDirtyWithCleanLayout(this);
 }
 
 void AXNodeObject::SelectedOptions(AXObjectVector& options) const {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index d9adf34c..8813a2b 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -2478,6 +2478,7 @@
 
   if (obj) {
     obj->ChildrenChangedWithCleanLayout();
+    modification_count_++;
     // TODO(accessibility) Only needed for <select> size changes.
     // This can turn into a DCHECK if the shadow DOM is used for <select>
     // elements instead of AXMenuList* and AXListBox* classes.
@@ -3608,7 +3609,7 @@
     DCHECK(!obj->IsDetached());
     if (!obj->NeedsToUpdateChildren()) {
       obj->SetNeedsToUpdateChildren();
-      PostNotification(obj, ax::mojom::blink::Event::kChildrenChanged);
+      MarkAXObjectDirty(obj);
     }
   }
 }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
index 63ef84b..c4f0116 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -680,8 +680,9 @@
   DCHECK(child);
   if (child->IsDetached())
     return;
-  if (AXObject* new_parent = object_cache_->RestoreParentOrPrune(child))
-    ChildrenChanged(new_parent);
+  if (AXObject* new_parent = object_cache_->RestoreParentOrPrune(child)) {
+    object_cache_->ChildrenChanged(new_parent);
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
index dcee88c4..be4c43a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_virtual_object.cc
@@ -69,7 +69,7 @@
 
 void AXVirtualObject::ChildrenChangedWithCleanLayout() {
   ClearChildren();
-  AXObjectCache().PostNotification(this, ax::mojom::Event::kChildrenChanged);
+  AXObjectCache().MarkAXObjectDirtyWithCleanLayout(this);
 }
 
 const AtomicString& AXVirtualObject::GetAOMPropertyOrARIAAttribute(
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
index f6dce7c..519d688 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
@@ -1274,6 +1274,10 @@
 
     // Log the UseCounter only when the WebID flag is enabled.
     UseCounter::Count(context, WebFeature::kFederatedCredentialManagement);
+    if (!resolver->DomWindow()->GetFrame()->IsMainFrame()) {
+      UseCounter::Count(resolver->GetExecutionContext(),
+                        WebFeature::kFederatedCredentialManagementIframe);
+    }
 
     int provider_index = 0;
     Vector<mojom::blink::IdentityProviderPtr> identity_provider_ptrs;
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track_impl.cc b/third_party/blink/renderer/modules/mediastream/media_stream_track_impl.cc
index 0a764291..5190dbe 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_track_impl.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_track_impl.cc
@@ -211,6 +211,20 @@
   return settings.display_surface;
 }
 
+WebString GetDisplaySurfaceString(
+    media::mojom::DisplayCaptureSurfaceType value) {
+  switch (value) {
+    case media::mojom::DisplayCaptureSurfaceType::MONITOR:
+      return WebString::FromUTF8("monitor");
+    case media::mojom::DisplayCaptureSurfaceType::WINDOW:
+      return WebString::FromUTF8("window");
+    case media::mojom::DisplayCaptureSurfaceType::BROWSER:
+      return WebString::FromUTF8("browser");
+  }
+  NOTREACHED();
+  return WebString();
+}
+
 }  // namespace
 
 MediaStreamTrack* MediaStreamTrackImpl::Create(ExecutionContext* context,
@@ -544,6 +558,11 @@
     capabilities->setFacingMode(facing_mode);
     capabilities->setResizeMode({WebMediaStreamTrack::kResizeModeNone,
                                  WebMediaStreamTrack::kResizeModeRescale});
+    const absl::optional<const MediaStreamDevice> source_device = device();
+    if (source_device && source_device->display_media_info) {
+      capabilities->setDisplaySurface(GetDisplaySurfaceString(
+          source_device->display_media_info->display_surface));
+    }
   }
   return capabilities;
 }
@@ -625,19 +644,8 @@
     image_capture_->GetMediaTrackSettings(settings);
 
   if (platform_settings.display_surface) {
-    WTF::String value;
-    switch (platform_settings.display_surface.value()) {
-      case media::mojom::DisplayCaptureSurfaceType::MONITOR:
-        value = "monitor";
-        break;
-      case media::mojom::DisplayCaptureSurfaceType::WINDOW:
-        value = "window";
-        break;
-      case media::mojom::DisplayCaptureSurfaceType::BROWSER:
-        value = "browser";
-        break;
-    }
-    settings->setDisplaySurface(value);
+    settings->setDisplaySurface(
+        GetDisplaySurfaceString(platform_settings.display_surface.value()));
   }
   if (platform_settings.logical_surface)
     settings->setLogicalSurface(platform_settings.logical_surface.value());
diff --git a/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl b/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl
index 63cd4ec..28ff542 100644
--- a/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl
+++ b/third_party/blink/renderer/modules/mediastream/media_track_capabilities.idl
@@ -40,4 +40,7 @@
     boolean              torch;
     // W3C Media Capture Extensions
     [RuntimeEnabled=MediaCaptureBackgroundBlur] sequence<boolean> backgroundBlur;
+    // Screen Capture API
+    // https://w3c.github.io/mediacapture-screen-share
+    [RuntimeEnabled=GetDisplayMedia] DOMString displaySurface;
 };
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 96355e1..d262619 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -69,6 +69,28 @@
   ]
 }
 
+blink_python_runner("runtime_feature_state_override_context") {
+  script = "../build/scripts/make_runtime_feature_state_override_context.py"
+
+  inputs = scripts_for_json5_files + [
+             "../build/scripts/make_runtime_feature_state_override_context.py",
+             "runtime_enabled_features.json5",
+             "../build/scripts/templates/runtime_feature_state_override_context.h.tmpl",
+             "../build/scripts/templates/runtime_feature_state_override_context.cc.tmpl",
+           ]
+  outputs = [
+    "$blink_platform_output_dir/runtime_feature_state/runtime_feature_state_override_context.h",
+    "$blink_platform_output_dir/runtime_feature_state/runtime_feature_state_override_context.cc",
+  ]
+
+  args = [
+    rebase_path("runtime_enabled_features.json5", root_build_dir),
+    "--output_dir",
+    rebase_path("$blink_platform_output_dir/runtime_feature_state",
+                root_build_dir),
+  ]
+}
+
 blink_python_runner("color_data") {
   script = "../build/scripts/gperf.py"
 
@@ -121,6 +143,7 @@
     ":color_data",
     ":font_family_names",
     ":runtime_enabled_features",
+    ":runtime_feature_state_override_context",
     "//third_party/blink/renderer/platform/network:make_generated",
   ]
 }
@@ -1546,7 +1569,8 @@
   # Add in the generated files.
   sources += get_target_outputs(":character_data") +
              get_target_outputs(":color_data") +
-             get_target_outputs(":font_family_names")
+             get_target_outputs(":font_family_names") +
+             get_target_outputs(":runtime_feature_state_override_context")
 
   foreach(_output, get_target_outputs(":runtime_enabled_features")) {
     if (get_path_info(_output, "extension") != "pickle") {
diff --git a/third_party/blink/renderer/platform/graphics/paint/display_item_client.h b/third_party/blink/renderer/platform/graphics/paint/display_item_client.h
index 762cde8..ac7c007 100644
--- a/third_party/blink/renderer/platform/graphics/paint/display_item_client.h
+++ b/third_party/blink/renderer/platform/graphics/paint/display_item_client.h
@@ -54,14 +54,9 @@
   // cached display items without calling this method.
   // See PaintController::ClientCacheIsValid() for more details.
   void Invalidate(
-      PaintInvalidationReason reason = PaintInvalidationReason::kFull) const {
-    // If a full invalidation reason is already set, do not overwrite it with
-    // a new reason.
-    if (IsFullPaintInvalidationReason(GetPaintInvalidationReason()) &&
-        // However, kUncacheable overwrites any other reason.
-        reason != PaintInvalidationReason::kUncacheable)
-      return;
-    paint_invalidation_reason_ = static_cast<uint8_t>(reason);
+      PaintInvalidationReason reason = PaintInvalidationReason::kLayout) const {
+    if (reason > GetPaintInvalidationReason())
+      paint_invalidation_reason_ = static_cast<uint8_t>(reason);
   }
 
   PaintInvalidationReason GetPaintInvalidationReason() const {
diff --git a/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator.cc b/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator.cc
index bb112f1..0cb4531b 100644
--- a/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator.cc
@@ -173,7 +173,7 @@
 
   if (!IsFullPaintInvalidationReason(reason) &&
       old_visual_rect.origin() != new_visual_rect.origin())
-    reason = PaintInvalidationReason::kGeometry;
+    reason = PaintInvalidationReason::kLayout;
 
   if (IsFullPaintInvalidationReason(reason)) {
     GenerateFullRasterInvalidation(client_id, old_visual_rect, new_visual_rect,
diff --git a/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc b/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
index 2dbb9c25..6af4e58e 100644
--- a/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/display_item_raster_invalidator_test.cc
@@ -63,8 +63,7 @@
 
 INSTANTIATE_PAINT_TEST_SUITE_P(DisplayItemRasterInvalidatorTest);
 
-TEST_P(DisplayItemRasterInvalidatorTest,
-       FullInvalidationWithoutGeometryChange) {
+TEST_P(DisplayItemRasterInvalidatorTest, FullInvalidationWithoutLayoutChange) {
   FakeDisplayItemClient& first =
       *MakeGarbageCollected<FakeDisplayItemClient>("first");
   FakeDisplayItemClient& second =
@@ -80,7 +79,7 @@
     DrawRect(context, first, kForegroundType, gfx::Rect(100, 150, 300, 300));
   }
 
-  first.Invalidate(PaintInvalidationReason::kStyle);
+  first.Invalidate();
   invalidator_.SetTracksRasterInvalidations(true);
   {
     RasterInvalidationCycleScope cycle_scope(GetPaintController(),
@@ -94,7 +93,7 @@
   EXPECT_THAT(GetRasterInvalidations(),
               UnorderedElementsAre(RasterInvalidationInfo{
                   first.Id(), "first", gfx::Rect(100, 100, 300, 350),
-                  PaintInvalidationReason::kStyle}));
+                  PaintInvalidationReason::kLayout}));
   invalidator_.SetTracksRasterInvalidations(false);
 }
 
@@ -114,7 +113,7 @@
     DrawRect(context, first, kForegroundType, gfx::Rect(100, 150, 300, 300));
   }
 
-  first.Invalidate(PaintInvalidationReason::kStyle);
+  first.Invalidate();
   invalidator_.SetTracksRasterInvalidations(true);
   {
     RasterInvalidationCycleScope cycle_scope(GetPaintController(),
@@ -129,10 +128,10 @@
               UnorderedElementsAre(
                   RasterInvalidationInfo{first.Id(), "first",
                                          gfx::Rect(100, 100, 300, 350),
-                                         PaintInvalidationReason::kStyle},
+                                         PaintInvalidationReason::kLayout},
                   RasterInvalidationInfo{first.Id(), "first",
                                          gfx::Rect(200, 100, 300, 350),
-                                         PaintInvalidationReason::kStyle}));
+                                         PaintInvalidationReason::kLayout}));
   invalidator_.SetTracksRasterInvalidations(false);
 }
 
@@ -457,10 +456,10 @@
                                          PaintInvalidationReason::kAppeared},
                   RasterInvalidationInfo{second.Id(), "second",
                                          gfx::Rect(200, 200, 50, 50),
-                                         PaintInvalidationReason::kFull},
+                                         PaintInvalidationReason::kLayout},
                   RasterInvalidationInfo{second.Id(), "second",
                                          gfx::Rect(150, 250, 100, 100),
-                                         PaintInvalidationReason::kFull}));
+                                         PaintInvalidationReason::kLayout}));
   invalidator_.SetTracksRasterInvalidations(false);
 
   invalidator_.SetTracksRasterInvalidations(true);
@@ -511,7 +510,7 @@
               UnorderedElementsAre(
                   RasterInvalidationInfo{first.Id(), "first",
                                          gfx::Rect(100, 100, 150, 150),
-                                         PaintInvalidationReason::kFull},
+                                         PaintInvalidationReason::kLayout},
                   RasterInvalidationInfo{second.Id(), "second",
                                          gfx::Rect(200, 200, 50, 50),
                                          PaintInvalidationReason::kAppeared}));
@@ -532,7 +531,7 @@
               UnorderedElementsAre(
                   RasterInvalidationInfo{first.Id(), "first",
                                          gfx::Rect(100, 100, 150, 150),
-                                         PaintInvalidationReason::kFull},
+                                         PaintInvalidationReason::kLayout},
                   RasterInvalidationInfo{
                       second.Id(), "second", gfx::Rect(200, 200, 50, 50),
                       PaintInvalidationReason::kDisappeared}));
@@ -661,7 +660,7 @@
                                          PaintInvalidationReason::kReordered},
                   RasterInvalidationInfo{container2.Id(), "container2",
                                          gfx::Rect(100, 200, 100, 100),
-                                         PaintInvalidationReason::kFull}));
+                                         PaintInvalidationReason::kLayout}));
   invalidator_.SetTracksRasterInvalidations(false);
 }
 
@@ -792,10 +791,10 @@
       UnorderedElementsAre(
           RasterInvalidationInfo{multicol.Id(), "multicol",
                                  gfx::Rect(100, 200, 100, 100),
-                                 PaintInvalidationReason::kFull},
+                                 PaintInvalidationReason::kLayout},
           RasterInvalidationInfo{multicol.Id(), "multicol",
                                  gfx::Rect(100, 100, 100, 100),
-                                 PaintInvalidationReason::kFull},
+                                 PaintInvalidationReason::kLayout},
           RasterInvalidationInfo{content.Id(), "content",
                                  UnionRects(rect1, UnionRects(rect2, rect3)),
                                  PaintInvalidationReason::kUncacheable}));
diff --git a/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h b/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h
index 717a0eac..beb8050 100644
--- a/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h
+++ b/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h
@@ -31,7 +31,7 @@
   // For CAP, this is set in PaintArtifactCompositor when converting chunk
   // raster invalidations to cc raster invalidations.
   gfx::Rect rect;
-  PaintInvalidationReason reason = PaintInvalidationReason::kFull;
+  PaintInvalidationReason reason = PaintInvalidationReason::kLayout;
 };
 
 inline bool operator==(const RasterInvalidationInfo& a,
diff --git a/third_party/blink/renderer/platform/graphics/paint_invalidation_reason.cc b/third_party/blink/renderer/platform/graphics/paint_invalidation_reason.cc
index f205eda..add3105 100644
--- a/third_party/blink/renderer/platform/graphics/paint_invalidation_reason.cc
+++ b/third_party/blink/renderer/platform/graphics/paint_invalidation_reason.cc
@@ -10,8 +10,8 @@
 
 namespace blink {
 
-static_assert(static_cast<uint8_t>(PaintInvalidationReason::kMax) < (1 << 7),
-              "PaintInvalidationReason must fit in 7 bits");
+static_assert(static_cast<uint8_t>(PaintInvalidationReason::kMax) < (1 << 6),
+              "PaintInvalidationReason must fit in 6 bits");
 
 const char* PaintInvalidationReasonToString(PaintInvalidationReason reason) {
   switch (reason) {
@@ -21,30 +21,26 @@
       return "incremental";
     case PaintInvalidationReason::kHitTest:
       return "hit testing change";
-    case PaintInvalidationReason::kFull:
-      return "full";
     case PaintInvalidationReason::kStyle:
       return "style change";
-    case PaintInvalidationReason::kBackplate:
-      return "backplate";
-    case PaintInvalidationReason::kGeometry:
-      return "geometry";
-    case PaintInvalidationReason::kCompositing:
-      return "compositing update";
+    case PaintInvalidationReason::kOutline:
+      return "outline";
+    case PaintInvalidationReason::kImage:
+      return "image";
     case PaintInvalidationReason::kBackground:
       return "background";
+    case PaintInvalidationReason::kBackplate:
+      return "backplate";
+    case PaintInvalidationReason::kLayout:
+      return "geometry";
     case PaintInvalidationReason::kAppeared:
       return "appeared";
     case PaintInvalidationReason::kDisappeared:
       return "disappeared";
-    case PaintInvalidationReason::kScroll:
-      return "scroll";
     case PaintInvalidationReason::kScrollControl:
       return "scroll control";
     case PaintInvalidationReason::kSelection:
       return "selection";
-    case PaintInvalidationReason::kOutline:
-      return "outline";
     case PaintInvalidationReason::kSubtree:
       return "subtree";
     case PaintInvalidationReason::kSVGResource:
@@ -53,8 +49,6 @@
       return "caret";
     case PaintInvalidationReason::kDocumentMarker:
       return "DocumentMarker change";
-    case PaintInvalidationReason::kImage:
-      return "image";
     case PaintInvalidationReason::kUncacheable:
       return "uncacheable";
     case PaintInvalidationReason::kJustCreated:
@@ -73,8 +67,6 @@
       return "paint property change";
     case PaintInvalidationReason::kFullLayer:
       return "full layer";
-    case PaintInvalidationReason::kForTesting:
-      return "for testing";
   }
   NOTREACHED();
   return "";
diff --git a/third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h b/third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h
index e7d303f..d9de0347 100644
--- a/third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h
+++ b/third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h
@@ -13,35 +13,51 @@
 
 namespace blink {
 
+// Reasons of paint invalidation and raster invalidation. A paint invalidation
+// reason (<= kLayoutMax) is set in renderer/core (mostly layout and paint)
+// on a DisplayItemClient to indicate it will paint differently from the
+// previous painted result. During raster invalidation, we use paint
+// invalidation reasons as raster invalidation reasons for display items,
+// and raster invalidation reasons (> kLayoutMax) for changes such as
+// reordering of display item and paint chunks.
 enum class PaintInvalidationReason : uint8_t {
   kNone,
+  // This is used for mere size change of LayoutBox that can be invalidated for
+  // the changed part instead of the whole box.
   kIncremental,
   // Hit test changes do not require raster invalidation.
   kHitTest,
-  // The following reasons will all cause full paint invalidation.
-  // Any unspecified reason of full invalidation.
-  kFull,
-  kSelection,
+  kNonFullMax = kHitTest,
+
+  // Non-layout full paint invalidation reasons.
+
   kStyle,
-  // Layout or visual geometry change.
+  kOutline,
+  kImage,
   kBackplate,
-  kGeometry,
-  kCompositing,
+  kBackground,
+  kSelection,
+  kCaret,
+  kNonLayoutMax = kCaret,
+
+  // Full paint invalidation reasons related to layout changes.
+
+  kLayout,
   kAppeared,
   kDisappeared,
-  kScroll,
   // Scroll bars, scroll corner, etc.
   kScrollControl,
-  kOutline,
   // The object is invalidated as a part of a subtree full invalidation (forced
   // by LayoutObject::SetSubtreeShouldDoFullPaintInvalidation()).
   kSubtree,
   kSVGResource,
-  kBackground,
-  kCaret,
+  // TODO(wangxianzhu): This should probably be a non-layout reason.
   kDocumentMarker,
-  kImage,
-  kUncacheable,
+  kLayoutMax = kDocumentMarker,
+
+  // The following are not used for paint invalidation, but for raster
+  // invalidation only.
+
   // The initial PaintInvalidationReason of a DisplayItemClient.
   kJustCreated,
   kReordered,
@@ -53,15 +69,30 @@
   // For tracking of direct raster invalidation of full composited layers. The
   // invalidation may be implicit, e.g. when a layer is created.
   kFullLayer,
-  kForTesting,
-  kMax = kForTesting,
+  // This needs to be the last reason because DisplayItemClient::Invalidate()
+  // requires this reason to override other reasons.
+  kUncacheable,
+  kMax = kUncacheable,
 };
 
 PLATFORM_EXPORT const char* PaintInvalidationReasonToString(
     PaintInvalidationReason);
 
-inline bool IsFullPaintInvalidationReason(PaintInvalidationReason reason) {
-  return reason >= PaintInvalidationReason::kFull;
+inline constexpr bool IsFullPaintInvalidationReason(
+    PaintInvalidationReason reason) {
+  return reason > PaintInvalidationReason::kNonFullMax;
+}
+
+inline constexpr bool IsNonLayoutFullPaintInvalidationReason(
+    PaintInvalidationReason reason) {
+  return reason > PaintInvalidationReason::kNonFullMax &&
+         reason <= PaintInvalidationReason::kNonLayoutMax;
+}
+
+inline constexpr bool IsLayoutPaintInvalidationReason(
+    PaintInvalidationReason reason) {
+  return reason > PaintInvalidationReason::kNonLayoutMax &&
+         reason <= PaintInvalidationReason::kLayoutMax;
 }
 
 PLATFORM_EXPORT std::ostream& operator<<(std::ostream&,
diff --git a/third_party/blink/renderer/platform/graphics/paint_invalidation_reason_test.cc b/third_party/blink/renderer/platform/graphics/paint_invalidation_reason_test.cc
index 8564780..466e5252 100644
--- a/third_party/blink/renderer/platform/graphics/paint_invalidation_reason_test.cc
+++ b/third_party/blink/renderer/platform/graphics/paint_invalidation_reason_test.cc
@@ -5,30 +5,67 @@
 #include "third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h"
 
 #include <sstream>
+
+#include "base/functional/function_ref.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
+namespace {
+
+using ReasonFunction = base::FunctionRef<void(PaintInvalidationReason)>;
+
+PaintInvalidationReason NextReason(PaintInvalidationReason r) {
+  return static_cast<PaintInvalidationReason>(static_cast<unsigned>(r) + 1);
+}
+
+void ForReasons(PaintInvalidationReason min,
+                PaintInvalidationReason max,
+                ReasonFunction f) {
+  for (auto i = min; i <= max; i = NextReason(i))
+    f(i);
+}
 
 TEST(PaintInvalidationReasonTest, ToString) {
-  for (auto i = PaintInvalidationReason::kNone;
-       i <= PaintInvalidationReason::kMax;
-       i = static_cast<PaintInvalidationReason>(static_cast<int>(i) + 1))
-    EXPECT_STRNE("", PaintInvalidationReasonToString(i));
+  ForReasons(PaintInvalidationReason::kNone, PaintInvalidationReason::kMax,
+             [](PaintInvalidationReason r) {
+               EXPECT_STRNE("", PaintInvalidationReasonToString(r));
+             });
 
   EXPECT_STREQ("none",
                PaintInvalidationReasonToString(PaintInvalidationReason::kNone));
-  EXPECT_STREQ("full",
-               PaintInvalidationReasonToString(PaintInvalidationReason::kFull));
+  EXPECT_STREQ("geometry", PaintInvalidationReasonToString(
+                               PaintInvalidationReason::kLayout));
 }
 
-TEST(PaintInvalidationReasonTest, StreamOutput) {
-  for (auto i = PaintInvalidationReason::kNone;
-       i <= PaintInvalidationReason::kMax;
-       i = static_cast<PaintInvalidationReason>(static_cast<int>(i) + 1)) {
-    std::stringstream string_stream;
-    string_stream << i;
-    EXPECT_EQ(PaintInvalidationReasonToString(i), string_stream.str());
-  }
+TEST(PaintInvalidationReasonTest, IsFullGeometryPaintInvalidationReason) {
+  ForReasons(PaintInvalidationReason::kNone,
+             PaintInvalidationReason::kNonFullMax,
+             [](PaintInvalidationReason r) {
+               EXPECT_FALSE(IsFullPaintInvalidationReason(r));
+               EXPECT_FALSE(IsNonLayoutFullPaintInvalidationReason(r));
+               EXPECT_FALSE(IsLayoutPaintInvalidationReason(r));
+             });
+  ForReasons(NextReason(PaintInvalidationReason::kNonFullMax),
+             PaintInvalidationReason::kNonLayoutMax,
+             [](PaintInvalidationReason r) {
+               EXPECT_TRUE(IsFullPaintInvalidationReason(r));
+               EXPECT_TRUE(IsNonLayoutFullPaintInvalidationReason(r));
+               EXPECT_FALSE(IsLayoutPaintInvalidationReason(r));
+             });
+  ForReasons(NextReason(PaintInvalidationReason::kNonLayoutMax),
+             PaintInvalidationReason::kLayoutMax,
+             [](PaintInvalidationReason r) {
+               EXPECT_TRUE(IsFullPaintInvalidationReason(r));
+               EXPECT_FALSE(IsNonLayoutFullPaintInvalidationReason(r));
+               EXPECT_TRUE(IsLayoutPaintInvalidationReason(r));
+             });
+  ForReasons(NextReason(PaintInvalidationReason::kLayoutMax),
+             PaintInvalidationReason::kMax, [](PaintInvalidationReason r) {
+               EXPECT_TRUE(IsFullPaintInvalidationReason(r));
+               EXPECT_FALSE(IsNonLayoutFullPaintInvalidationReason(r));
+               EXPECT_FALSE(IsLayoutPaintInvalidationReason(r));
+             });
 }
 
+}  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 54baeed..33f5f98 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -602,12 +602,6 @@
       name: "CorsRFC1918",
     },
     {
-      name: "CrossOriginOpenerPolicyReporting",
-      origin_trial_feature_name: "CrossOriginOpenerPolicyReporting",
-      origin_trial_allows_third_party: true,
-      status: "experimental",
-    },
-    {
       // Allows positioning a positioned element relative to another one.
       // https://drafts.csswg.org/css-anchor-1/
       name: "CSSAnchorPositioning",
@@ -1171,6 +1165,11 @@
       status: "test",
     },
     {
+      name: "FastComparePositions",
+      status: "stable",
+      base_feature: "FastComparePositions",
+    },
+    {
       name: "FastPositionIterator",
       status: "stable",
       base_feature: "FastPositionIterator",
diff --git a/third_party/blink/renderer/platform/widget/frame_widget.h b/third_party/blink/renderer/platform/widget/frame_widget.h
index 8a92e32..669b180 100644
--- a/third_party/blink/renderer/platform/widget/frame_widget.h
+++ b/third_party/blink/renderer/platform/widget/frame_widget.h
@@ -283,6 +283,12 @@
   // CompositorFrames.  See https://crbug.com/1232173 for more details.
   virtual void SetMayThrottleIfUndrawnFrames(
       bool may_throttle_if_undrawn_frames) = 0;
+
+  // Returns, in physical pixels, the amount that the widget has been resized
+  // by the virtual keyboard. The virtual keyboard always insets a widget from
+  // the bottom so only the height can be affected. Only the outermost main
+  // frame's widget returns a non-zero value.
+  virtual int GetVirtualKeyboardResizeHeight() const = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 1ee5f42..aa766a4 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -749,7 +749,6 @@
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/fire-error-event-exception.html [ Slow ]
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/get-databases.any.html [ Slow ]
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/idb-explicit-commit.any.html [ Slow ]
-crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/idb-explicit-commit.any.worker.html [ Slow ]
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/idbindex_getAll.html [ Slow ]
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/idbindex_getAllKeys.html [ Slow ]
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/keygenerator-explicit.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 7243662..829cc5a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1512,7 +1512,6 @@
 crbug.com/591099 [ Mac ] external/wpt/css/css-text/text-transform/text-transform-shaping-003.html [ Failure ]
 crbug.com/591099 [ Mac ] external/wpt/css/css-text/white-space/control-chars-00C.html [ Failure ]
 crbug.com/591099 [ Mac ] external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Failure ]
-crbug.com/591099 [ Mac ] external/wpt/css/css-transforms/transform-inline-001.html [ Failure ]
 crbug.com/591099 [ Mac ] external/wpt/css/css-ui/text-overflow-027.html [ Failure ]
 crbug.com/591099 [ Mac ] external/wpt/css/css-ui/text-overflow-028.html [ Failure ]
 crbug.com/591099 [ Mac ] external/wpt/css/css-writing-modes/bidi-embed-011.html [ Failure ]
@@ -2988,7 +2987,6 @@
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-010.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-011.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-012.xht [ Failure ]
-crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-016.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-020.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-179.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-192.xht [ Failure ]
@@ -2997,7 +2995,6 @@
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-195.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-196.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-197.xht [ Failure ]
-crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-205.xht [ Failure ]
 
 # Custom-elements
 crbug.com/1351482 external/wpt/custom-elements/form-associated/ElementInternals-target-element-is-held-strongly.html [ Timeout ]
@@ -3186,7 +3183,6 @@
 crbug.com/626703 [ Mac10.14 ] external/wpt/pointerevents/pointerevent_pointercapture_in_frame.html?pen [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/pointerevents/pointerevent_pointercapture_in_frame.html?pen [ Timeout ]
 crbug.com/626703 [ Win ] external/wpt/websockets/stream/tentative/constructor.any.serviceworker.html?wss [ Failure Timeout ]
-crbug.com/626703 [ Win ] external/wpt/websockets/opening-handshake/005.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCPeerConnection-ondatachannel.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-ondatachannel.html [ Skip Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/protocol/rtp-clockrate.html [ Skip Timeout ]
@@ -4631,7 +4627,6 @@
 crbug.com/1112508 fast/forms/number/number-wheel-event.html [ Failure ]
 
 # Sheriff 2020-07-20
-crbug.com/1107722 [ Mac ] http/tests/devtools/tracing/timeline-time/timeline-time.js [ Failure Pass ]
 crbug.com/1107572 [ Mac ] http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.js [ Failure Pass ]
 crbug.com/1107572 [ Mac ] http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.js [ Failure Pass ]
 crbug.com/1107572 [ Mac ] http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.js [ Failure Pass ]
@@ -6244,7 +6239,6 @@
 crbug.com/1359541 [ Win ] virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-scrolling-on-div-custom-scrollbar.html [ Failure Pass Timeout ]
 
 # Disable devtool flake on Mac11,12,10.15
-crbug.com/1363259 [ Mac11 ] http/tests/devtools/network/network-initiator.js [ Failure Pass ]
 crbug.com/1363259 [ Mac12 ] http/tests/devtools/network/network-initiator.js [ Failure Pass ]
 crbug.com/1363259 [ Mac10.15 ] http/tests/devtools/network/network-initiator.js [ Failure Pass ]
 
@@ -6870,7 +6864,6 @@
 
 # Sheriff 2022-11-17
 crbug.com/1385642 [ Linux ] external/wpt/css/css-values/calc-in-media-queries-with-mixed-units.html [ Failure Pass Skip Timeout ]
-crbug.com/1385681 external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html [ Failure Pass ]
 crbug.com/1372166 fast/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html [ Failure Pass ]
 crbug.com/1385497 http/tests/inspector-protocol/tracing/page-load-metrics.js [ Failure Pass ]
 crbug.com/1349215 external/wpt/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html [ Skip Timeout ]
diff --git a/third_party/blink/web_tests/accessibility/aria-owns-sends-notification.html b/third_party/blink/web_tests/accessibility/aria-owns-sends-notification.html
index eaf63d69..b51a093 100644
--- a/third_party/blink/web_tests/accessibility/aria-owns-sends-notification.html
+++ b/third_party/blink/web_tests/accessibility/aria-owns-sends-notification.html
@@ -13,7 +13,6 @@
       assert_equals(axFutureParent.childrenCount, 0);
 
       var expected_notifications = new Set();
-      expected_notifications.add("ChildrenChanged");
       expected_notifications.add("MarkDirty");
 
       while (expected_notifications.size) {
@@ -35,7 +34,7 @@
     var child = document.createElement("li");
     child.id = "future_child";
     futureParent.parentElement.appendChild(child);
-}, "A children changed notification is fired when an aria-owned child gets added to the tree.");
+}, "A mark dirty notification is fired when an aria-owned child gets added to the tree.");
 </script>
 
 <div id="container2">
@@ -54,7 +53,7 @@
     var axList1 = accessibilityController.accessibleElementById("list1");
     assert_equals(axList1.childrenCount, 0, "No children before setting aria-owns");
     var listener = t.step_func((notification) => {
-        assert_equals(notification, "ChildrenChanged");
+        assert_equals(notification, "MarkDirty");
         assert_equals(axList1.childrenCount, 1, "One child after setting aria-owns");
 
         axList1.removeNotificationListener(listener);
@@ -64,7 +63,7 @@
 
     var list1 = document.getElementById("list1");
     list1.setAttribute("aria-owns", "item1");
-}, "A children changed notification is fired when an aria-owned attribute is added to an element that causes it to reparent another element to become its child.");
+}, "A mark dirty notification is fired when an aria-owned attribute is added to an element that causes it to reparent another element to become its child.");
 </script>
 
 <div id="container3">
@@ -85,7 +84,7 @@
     var axList2 = accessibilityController.accessibleElementById("newlist2");
     assert_equals(axList2.childrenCount, 1);
     var listener = t.step_func((notification) => {
-        assert_equals(notification, "ChildrenChanged");
+        assert_equals(notification, "MarkDirty");
         assert_equals(axList2.childrenCount, 0);
         assert_equals(axList1.childrenCount, 1);
 
@@ -97,5 +96,5 @@
     list1.setAttribute("aria-owns", "newitem1");
     assert_equals(axList1.childrenCount, 1);
     assert_equals(axList2.childrenCount, 0);
-}, "A children changed notification is fired on the old parent when one of its children gets reparented to another element due to aria-owns.");
+}, "A mark dirty notification is fired on the old parent when one of its children gets reparented to another element due to aria-owns.");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/.well-known/attribution-reporting/debug/verbose b/third_party/blink/web_tests/external/wpt/.well-known/attribution-reporting/debug/verbose
new file mode 100644
index 0000000..7267cb10
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/.well-known/attribution-reporting/debug/verbose
@@ -0,0 +1,8 @@
+"""Endpoint to receive and return verbose debug reports."""
+from importlib import import_module
+
+reports = import_module('attribution-reporting.resources.reports')
+
+
+def main(request, response):
+  return reports.handle_reports(request)
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-fallback-grid-001.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-fallback-grid-001.html
new file mode 100644
index 0000000..f5ab425
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-fallback-grid-001.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#anchor-pos">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-1/#fallback">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#abspos-items">
+<link rel="author" href="mailto:kojii@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+  position: relative;
+}
+.grid {
+  display: grid;
+  grid-template-columns: repeat(4, 100px);
+  grid-template-rows: 50px 100px 50px 50px;
+}
+.item {
+  background: lightgray;
+}
+.spacer {
+  background: yellow;
+}
+.anchor1 {
+  anchor-name: --a1;
+  background: orange;
+  margin-left: 15px;
+  width: 20px;
+  height: 30px;
+}
+.target {
+  grid-column: 2 / 4;
+  grid-row: 2 / 4;
+  position: absolute;
+  position-fallback: --fallback1;
+  width: 100px;
+  height: 100px;
+  background: lime;
+  opacity: .2;
+}
+@position-fallback --fallback1 {
+  @try { /* Position to the left of the anchor. */
+    right: anchor(--a1 left);
+    top: anchor(--a1 top);
+  }
+  @try { /* Position to the right of the anchor with the wider width than CB. */
+    left: anchor(--a1 right);
+    top: anchor(--a1 top);
+    width: 250px;
+  }
+  @try { /* Position to the right of the anchor. This entry should succeed. */
+    left: anchor(--a1 right);
+    top: anchor(--a1 top);
+  }
+  @try { /* Zero-sized, the last entry wins if none succeeded. */
+    left: 0;
+    top: 0;
+    width: 0;
+    height: 0;
+  }
+}
+</style>
+<body onload="checkLayout('.target')">
+  <div>
+    <div class="spacer" style="height: 10px"></div>
+    <div class="grid cb">
+      <div class="item">1</div>
+      <div class="item">2</div>
+      <div class="item">3</div>
+      <div class="item">4</div>
+      <div class="item">5</div>
+      <div class="item">
+        <div class="spacer" style="height: 20px"></div>
+        <div class="anchor1"></div>
+      </div>
+      <div class="item">7</div>
+      <div class="item">8</div>
+      <div class="item">9</div>
+      <div class="item">10</div>
+      <div class="item">11</div>
+      <div class="item">12</div>
+      <div class="item">13</div>
+      <div class="item">14</div>
+      <div class="item">15</div>
+      <div class="item">16</div>
+
+      <div class="target"
+           data-offset-x=135 data-offset-y=70
+           data-expected-height=100></div>
+    </div>
+  </div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html
index 576c961..551b83d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html
@@ -23,6 +23,7 @@
 }
 #hidden {
   background: red;
+  view-transition-name: hidden;
 }
 
 html::view-transition-group(hidden) { animation-duration: 300s; }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html
index 52a7fc9..ce9eb47 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html
@@ -34,7 +34,7 @@
 html::view-transition-group(before) { animation-duration: 0s; }
 html::view-transition-image-pair(before) { filter: invert(1); }
 html::view-transition-new(before) { animation-duration: 0s; }
-html::view-transition-old(*) { animation-duration: 0s; }
+html::view-transition-old(before) { animation-duration: 0s; }
 
 html::view-transition-group(after) { animation-duration: 0s; }
 html::view-transition-image-pair(after) { filter: invert(1); }
@@ -55,13 +55,12 @@
 async function runTest() {
   hidden.style.viewTransitionName = "hidden";
   before.style.viewTransitionName = "before";
-  document.startViewTransition(() => {
+  let transition = document.startViewTransition(() => {
     before.remove();
     hidden.style.viewTransitionName = "";
     after.style.viewTransitionName = "after";
-
-    requestAnimationFrame(() => requestAnimationFrame(takeScreenshot))
   });
+  transition.ready.then(() => requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
 }
 onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html
index f896f23..175a1bb 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html
@@ -15,6 +15,7 @@
 ::view-transition-group(*) {
   background-color: inherit;
   color: blue;
+  animation-duration: 0.321s;
 }
 
 ::view-transition-image-pair(*) {
@@ -36,12 +37,16 @@
 
       assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").backgroundColor, "rgb(255, 0, 0)", "group");
       assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").color, "rgb(0, 0, 255)", "group");
+      assert_equals(getComputedStyle(document.documentElement, ":view-transition-group(root)").animationDuration, "0.321s", "group");
 
       assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(root)").color, "rgb(0, 0, 255)", "wrapper");
       assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(root)").overflowX, "clip", "wrapper");
+      assert_equals(getComputedStyle(document.documentElement, ":view-transition-image-pair(root)").animationDuration, "0.321s", "wrapper");
 
       assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(root)").overflowX, "clip", "outgoing");
+      assert_equals(getComputedStyle(document.documentElement, ":view-transition-old(root)").animationDuration, "0.321s", "outgoing");
       assert_equals(getComputedStyle(document.documentElement, ":view-transition-new(root)").overflowX, "clip", "incoming");
+      assert_equals(getComputedStyle(document.documentElement, ":view-transition-new(root)").animationDuration, "0.321s", "incoming");
     });
     await transition.finished;
     resolve();
diff --git a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
index 9d156b0..ba1d56a 100644
--- a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 59 tests; 58 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 60 tests; 59 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS getDisplayMedia in navigator.mediaDevices
 FAIL getDisplayMedia() must require user activation assert_unreached: Should have rejected: getDisplayMedia should have returned an already-rejected promise. Reached unreachable code
 PASS getDisplayMedia({"video":true}) must succeed with video
@@ -59,5 +59,6 @@
 PASS suppressLocalAudioPlayback is supported
 PASS getDisplayMedia({"audio":{"suppressLocalAudioPlayback":true}}) with getSettings
 PASS getDisplayMedia({"audio":{"suppressLocalAudioPlayback":false}}) with getSettings
+PASS getDisplayMedia() with getCapabilities
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
index 426235a..095b98d 100644
--- a/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
+++ b/third_party/blink/web_tests/external/wpt/screen-capture/getdisplaymedia.https.html
@@ -267,4 +267,13 @@
   });
 }
 
+promise_test(async t => {
+  const stream = await getDisplayMedia({video: true});
+  t.add_cleanup(() => stopTracks(stream));
+  const capabilities = stream.getVideoTracks()[0].getCapabilities();
+  assert_any(
+      assert_equals, capabilities.displaySurface,
+      ['monitor', 'window', 'browser']);
+}, 'getDisplayMedia() with getCapabilities');
+
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-preventDefault.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-preventDefault.tentative.html
index 8fc159d..d6c61ef 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-preventDefault.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/navigation-api-preventDefault.tentative.html
@@ -16,16 +16,19 @@
   </main>
   <script>
     const link = document.getElementById("link");
-    testNavigationApiNotDetected(
-      "Aborted navigate event is not a soft navigation",
-      e => {
+    testSoftNavigationNotDetected({
+      testName: "Aborted navigate event is not a soft navigation",
+      eventHandler: e => {
         timestamps[counter]["eventStart"] = performance.now();
         e.intercept({handler: async () => {
           await addImageToMain();
           main.appendChild(img);
         }});
         e.preventDefault();
-      }, link);
+      },
+      eventTarget: navigation,
+      eventName: "navigate",
+      link: link});
   </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/replacestate-null-then-push.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/replacestate-null-then-push.tentative.html
new file mode 100644
index 0000000..8a81c6b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/replacestate-null-then-push.tentative.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Detect soft navigation with replaceState that has a null URL, then
+       pushState with the URL.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/soft-navigation-helper.js"></script>
+</head>
+<body>
+  <main id=main>
+  <a id=link>Click me!</a>
+  </main>
+  <script>
+    const link = document.getElementById("link");
+    testSoftNavigation({
+      addContent: async (url) => {
+        await addImageToMain();
+        history.pushState({}, '', url);
+      },
+      link: link,
+      pushState: async (url) =>{
+        history.replaceState({}, '');
+      },
+      test: "Detect soft navigation with replaceState that has a null URL," +
+            " then pushState with the URL"});
+  </script>
+</body>
+</html>
+
+
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/replacestate.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/replacestate.tentative.html
new file mode 100644
index 0000000..42e9a71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/replacestate.tentative.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Detect soft navigation with replaceState.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/soft-navigation-helper.js"></script>
+</head>
+<body>
+  <main id=main>
+  <a id=link>Click me!</a>
+  </main>
+  <script>
+    const link = document.getElementById("link");
+    testSoftNavigation({
+      addContent: async () => {
+        await addImageToMain();
+      },
+      link: link,
+      pushState: (url)=>{history.replaceState({}, '', url);},
+      test: "Detect soft navigation with replaceState"});
+  </script>
+</body>
+</html>
+
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js
index 08e9fd4..a24fe22 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-helper.js
@@ -58,22 +58,24 @@
   }, testName);
 };
 
-const testNavigationApiNotDetected =
-    (testName, navigateEventHandler, link) => {
-      promise_test(async t => {
-        const preClickLcp = await getLcpEntries();
-        navigation.addEventListener('navigate', navigateEventHandler);
-        click(link);
-        await new Promise((resolve, reject) => {
-          (new PerformanceObserver(() => reject())).observe({
-            type: 'soft-navigation'
-          });
-          t.step_timeout(resolve, 1000);
+const testSoftNavigationNotDetected = options => {
+    promise_test(async t => {
+      const preClickLcp = await getLcpEntries();
+      options.eventTarget.addEventListener(options.eventName, options.eventHandler);
+      click(options.link);
+      await new Promise((resolve, reject) => {
+        (new PerformanceObserver(() =>
+            reject("Soft navigation should not be triggered"))).observe({
+          type: 'soft-navigation',
+          buffered: true
         });
-        assert_equals(
-            document.softNavigations, 0, 'Soft Navigation not detected');
-      }, testName);
-    };
+        t.step_timeout(resolve, 1000);
+      });
+      assert_equals(
+          document.softNavigations, 0, 'Soft Navigation not detected');
+    }, options.testName);
+  };
+
 const runEntryValidations = async preClickLcp => {
   await doubleRaf();
   validatePaintEntries('first-contentful-paint');
@@ -109,14 +111,11 @@
     // Jump through a task, to ensure task tracking is working properly.
     await new Promise(r => t.step_timeout(r, 0));
 
-    // Fetch some content
-    const response = await fetch("/soft-navigation-heuristics/resources/content.json");
-    const json = await response.json();
-
+    const url = URL + "?" + counter;
     if (pushState) {
       // Change the URL
       if (pushUrl) {
-        pushState(URL + "?" + counter);
+        pushState(url);
       } else {
         pushState();
       }
@@ -125,7 +124,7 @@
     // Wait 10 ms to make sure the timestamps are correct.
     await new Promise(r => t.step_timeout(r, 10));
 
-    await addContent(json);
+    await addContent(url);
     ++counter;
 
     clicked = true;
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-detection-main-descendent.tentative.html.ini b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-detection-main-descendent.tentative.html.ini
deleted file mode 100644
index 78289d8..0000000
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-detection-main-descendent.tentative.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[soft-navigation-detection-main-descendent.tentative.html]
-  [Detect soft navigation adding content to a main descendent.]
-    expected: [PASS, FAIL]
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-no-url.tentative.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-no-url.tentative.html
index d1a1111..a0055c6 100644
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-no-url.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-no-url.tentative.html
@@ -15,14 +15,16 @@
   </main>
   <script>
     const link = document.getElementById("link");
-    testSoftNavigation({
-      addContent: () => {
+    testSoftNavigationNotDetected({
+      eventHandler: url => {
         addTextToDivOnMain();
+        history.pushState({}, '');
       },
       link: link,
-      pushUrl: false,
-      test: "Test that a soft navigation is detected when a URL is not passed"
-        + " to the history API."});
+      eventName: "click",
+      eventTarget: link,
+      testName: "Test that a soft navigation is not detected when a URL is not"
+        + " passed to the history API."});
   </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-no-url.tentative.html.ini b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-no-url.tentative.html.ini
deleted file mode 100644
index f33f2b1..0000000
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/soft-navigation-no-url.tentative.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[soft-navigation-no-url.tentative.html]
-  [Detect simple soft navigation.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/svg/styling/presentation-attributes.js b/third_party/blink/web_tests/external/wpt/svg/styling/presentation-attributes.js
index 7bf77cb..96d9568e3 100644
--- a/third_party/blink/web_tests/external/wpt/svg/styling/presentation-attributes.js
+++ b/third_party/blink/web_tests/external/wpt/svg/styling/presentation-attributes.js
@@ -356,6 +356,10 @@
   svg.append(e);
   let propertyValueBefore = getComputedStyle(e).getPropertyValue(property);
   e.setAttribute(attribute, value);
+  // Also set another attribute that is likely to be a presentation attribute,
+  // in order to provoke bugs.
+  const otherAttribute = attribute === 'stroke' ? 'fill' : 'stroke';
+  e.setAttribute(otherAttribute, 'red');
   let propertyValueAfter = getComputedStyle(e).getPropertyValue(property);
   e.remove();
   return propertyValueBefore != propertyValueAfter;
diff --git a/third_party/blink/web_tests/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
deleted file mode 100644
index 8125bf1..0000000
--- a/third_party/blink/web_tests/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS share() is disabled by permissions policy cross-origin
-PASS canShare() returns false when not allowed by permissions policy cross-origin
-FAIL canShare() returns false when not allowed by permissions policy cross-origin with empty data assert_equals: Expected true, is it can now share. expected true but got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html b/third_party/blink/web_tests/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html
index 148581d..78562419 100644
--- a/third_party/blink/web_tests/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html
@@ -90,7 +90,7 @@
       const iframe = await loadIframe(
         t,
         crossOriginSrc,
-        `web-share=("${crossOrigin}")`
+        `web-share ${crossOrigin}`
       );
       iframe.contentWindow.postMessage(
         { action: "canShare", data: shareData },
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-av1.html b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-av1.html
new file mode 100644
index 0000000..24cfcb8f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-av1.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>AV1 scalabilityMode</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/webrtc/RTCRtpParameters-helper.js"></script>
+<script src="/webrtc/RTCPeerConnection-helper.js"></script>
+<script src="/webrtc-svc/svc-helper.js"></script>
+<script>
+  'use strict';
+
+  createScalabilityTest('video/AV1', [
+    "L1T1",
+    "L1T2",
+    "L1T3",
+    "L2T1",
+    "L2T2",
+    "L2T3",
+    "L3T1",
+    "L3T2",
+    "L3T3",
+    "L2T1h",
+    "L2T2h",
+    "L2T3h",
+    "S2T1",
+    "S2T2",
+    "S2T3",
+    "S2T1h",
+    "S2T2h",
+    "S2T3h",
+    "S3T1",
+    "S3T2",
+    "S3T3",
+    "S3T1h",
+    "S3T2h",
+    "S3T3h",
+    "L2T2_KEY",
+    "L2T3_KEY",
+    "L3T2_KEY",
+    "L3T3_KEY"
+  ]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-expected.txt
index 79d1d575..816a2534 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-expected.txt
@@ -1,30 +1,10 @@
 This is a testharness.js-based test.
-PASS [0] video/VP8 - L1T2 should produce valid video content
-PASS [1] video/VP8 - L1T3 should produce valid video content
-PASS [2] video/VP9 - L1T2 should produce valid video content
-PASS [3] video/VP9 - L1T3 should produce valid video content
-PASS [4] video/AV1 - L1T2 should produce valid video content
-PASS [5] video/AV1 - L1T3 should produce valid video content
-PASS [6] video/AV1 - L2T1 should produce valid video content
-PASS [7] video/AV1 - L2T1h should produce valid video content
-PASS [8] video/AV1 - L2T1_KEY should produce valid video content
-PASS [9] video/AV1 - L2T2 should produce valid video content
-PASS [10] video/AV1 - L2T2_KEY should produce valid video content
-PASS [11] video/AV1 - L2T2_KEY_SHIFT should produce valid video content
-PASS [12] video/AV1 - L3T1 should produce valid video content
-PASS [13] video/AV1 - L3T3 should produce valid video content
-PASS [14] video/AV1 - L3T3_KEY should produce valid video content
-PASS [15] video/AV1 - S2T1 should produce valid video content
 PASS Setting and updating scalabilityMode to a legal value should be accepted
 PASS Sender capabilities should include at least some scalability modes
 PASS Not setting sendEncodings results in no mode info before negotiation
 PASS Not setting a scalability mode results in no mode set before negotiation
 FAIL Not setting a scalability mode results in some mode set after negotiation assert_true: expected true got false
-FAIL Setting a scalability mode to nonsense throws an exception assert_throws_dom: function "() => {
-    pc.addTransceiver('video', {
-      sendEncodings: [{scalabilityMode: 'TotalNonsense'}],
-    });
-  }" did not throw
+PASS Setting a scalability mode to nonsense throws an exception
 FAIL L3T3 on VP8 should return something other than L3T3 assert_not_equals: got disallowed value "L3T3"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-h264.html b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-h264.html
new file mode 100644
index 0000000..2a595a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-h264.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>H264 scalabilityMode</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/webrtc/RTCRtpParameters-helper.js"></script>
+<script src="/webrtc/RTCPeerConnection-helper.js"></script>
+<script src="/webrtc-svc/svc-helper.js"></script>
+<script>
+  'use strict';
+
+  createScalabilityTest('video/H264', [
+    "L1T1",
+    "L1T2",
+    "L1T3"
+  ]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-vp8.html b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-vp8.html
new file mode 100644
index 0000000..1708ab1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-vp8.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>VP8 scalabilityMode</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/webrtc/RTCRtpParameters-helper.js"></script>
+<script src="/webrtc/RTCPeerConnection-helper.js"></script>
+<script src="/webrtc-svc/svc-helper.js"></script>
+<script>
+  'use strict';
+
+  createScalabilityTest('video/VP8', [
+    "L1T1",
+    "L1T2",
+    "L1T3"
+  ]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-vp9.html b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-vp9.html
new file mode 100644
index 0000000..f1f4923
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability-vp9.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>VP9 scalabilityMode</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/webrtc/RTCRtpParameters-helper.js"></script>
+<script src="/webrtc/RTCPeerConnection-helper.js"></script>
+<script src="/webrtc-svc/svc-helper.js"></script>
+<script>
+  'use strict';
+
+  createScalabilityTest('video/VP9', [
+    "L1T1",
+    "L1T2",
+    "L1T3",
+    "L2T1",
+    "L2T2",
+    "L2T3",
+    "L3T1",
+    "L3T2",
+    "L3T3",
+    "L2T1h",
+    "L2T2h",
+    "L2T3h",
+    "S2T1",
+    "S2T2",
+    "S2T3",
+    "S2T1h",
+    "S2T2h",
+    "S2T3h",
+    "S3T1",
+    "S3T2",
+    "S3T3",
+    "S3T1h",
+    "S3T2h",
+    "S3T3h",
+    "L2T2_KEY",
+    "L2T3_KEY",
+    "L3T2_KEY",
+    "L3T3_KEY"
+  ]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability.html b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability.html
index c32a128..d8b1c6e 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc-svc/RTCRtpParameters-scalability.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <meta charset=utf-8>
+<meta name="timeout" content="long">
 <title>RTCRtpParameters encodings</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
@@ -12,46 +13,6 @@
   // Test is based on the following editor draft:
   // https://w3c.github.io/webrtc-svc/
 
-  // Get the first encoding in param.encodings.
-  // Asserts that param.encodings has at least one element.
-  function getFirstEncoding(param) {
-    const { encodings } = param;
-    assert_equals(encodings.length, 1);
-    return encodings[0];
-  }
-
-  const capabilities = RTCRtpSender.getCapabilities('video');
-  let index = 0;
-  for (const codec of capabilities.codecs) {
-    if ('scalabilityModes' in codec && codec.scalabilityModes.length > 0) {
-      for (const scalabilityMode of codec.scalabilityModes) {
-        promise_test(async t => {
-          const v = document.createElement('video');
-          v.autoplay = true;
-          const pc1 = new RTCPeerConnection();
-          const pc2 = new RTCPeerConnection();
-          t.add_cleanup(() => pc1.close());
-          t.add_cleanup(() => pc2.close());
-          const stream1 = await getNoiseStream({ video: { signal: 100 , width: 60, height: 60} });
-          const [track1] = stream1.getTracks();
-          t.add_cleanup(() => track1.stop());
-          const transceiver = pc1.addTransceiver(track1, {
-            sendEncodings: [{ scalabilityMode: scalabilityMode }],
-          });
-          transceiver.setCodecPreferences([codec]);
-          const haveTrackEvent = new Promise(r => pc2.ontrack = r);
-          exchangeIceCandidates(pc1, pc2);
-          await exchangeOfferAnswer(pc1, pc2);
-          v.srcObject = new MediaStream([(await haveTrackEvent).track]);
-          await new Promise(r => v.onloadedmetadata = r);
-          await detectSignal(t, v, 100);
-          const sendParams = pc1.getSenders()[0].getParameters();
-          assert_equals(sendParams.encodings[0].scalabilityMode, scalabilityMode);
-        }, `[${index++}] ${codec.mimeType} - ${scalabilityMode} should produce valid video content`);
-      }
-    }
-  }
-
   promise_test(async t => {
     const pc = new RTCPeerConnection();
     t.add_cleanup(() => pc.close());
@@ -84,81 +45,78 @@
     assert_true(svcSupported);
   }, `Sender capabilities should include at least some scalability modes`);
 
-promise_test(async t => {
-  const pc = new RTCPeerConnection();
-  t.add_cleanup(() => pc.close());
-  const { sender } = pc.addTransceiver('video');
-  const param = sender.getParameters();
-  assert_equals(param.encodings.length, 0);
-}, 'Not setting sendEncodings results in no mode info before negotiation');
-
-promise_test(async t => {
-  const pc = new RTCPeerConnection();
-  t.add_cleanup(() => pc.close());
-  const { sender } = pc.addTransceiver('video', {
-    sendEncodings: [{}],
-  });
-  const param = sender.getParameters();
-  const encoding = getFirstEncoding(param);
-
-  assert_true(!('scalabilityMode' in encoding));
-}, 'Not setting a scalability mode results in no mode set before negotiation');
-
-promise_test(async t => {
-  const pc1 = new RTCPeerConnection();
-  const pc2 = new RTCPeerConnection();
-  t.add_cleanup(() => pc1.close());
-  t.add_cleanup(() => pc2.close());
-  const { sender } = pc1.addTransceiver('video', {
-    sendEncodings: [{}],
-  });
-  const param = sender.getParameters();
-  const encoding = getFirstEncoding(param);
-
-  exchangeIceCandidates(pc1, pc2);
-  await exchangeOfferAnswer(pc1, pc2);
-  const param2 = sender.getParameters();
-  const encoding2 = getFirstEncoding(param);
-  assert_true('scalabilityMode' in encoding2);
-}, 'Not setting a scalability mode results in some mode set after negotiation');
-
-promise_test(async t => {
+  promise_test(async t => {
     const pc = new RTCPeerConnection();
-  t.add_cleanup(() => pc.close());
-  assert_throws_dom('OperationError', () => {
-    pc.addTransceiver('video', {
-      sendEncodings: [{scalabilityMode: 'TotalNonsense'}],
+    t.add_cleanup(() => pc.close());
+    const { sender } = pc.addTransceiver('video');
+    const param = sender.getParameters();
+    assert_equals(param.encodings.length, 0);
+  }, 'Not setting sendEncodings results in no mode info before negotiation');
+
+  promise_test(async t => {
+    const pc = new RTCPeerConnection();
+    t.add_cleanup(() => pc.close());
+    const { sender } = pc.addTransceiver('video', {
+      sendEncodings: [{}],
     });
-  });
-}, 'Setting a scalability mode to nonsense throws an exception');
+    const param = sender.getParameters();
+    const encoding = getFirstEncoding(param);
 
+    assert_true(!('scalabilityMode' in encoding));
+  }, 'Not setting a scalability mode results in no mode set before negotiation');
 
-promise_test(async t => {
-  const v = document.createElement('video');
-  v.autoplay = true;
-  const pc1 = new RTCPeerConnection();
-  const pc2 = new RTCPeerConnection();
-  t.add_cleanup(() => pc1.close());
-  t.add_cleanup(() => pc2.close());
-  const transceiver = pc1.addTransceiver('video', {
-    sendEncodings: [{ scalabilityMode: 'L3T3' }],
-  });
-  // Before negotiation, the mode should be preserved.
-  const param = transceiver.sender.getParameters();
-  const encoding = getFirstEncoding(param);
-  assert_true('scalabilityMode' in encoding);
-  // If L3T3 is not supported at all, abort test.
-  assert_implements_optional(encoding.scalabilityMode === 'L3T3');
-  // Pick a codec known to not have L3T3 support
-  const capabilities = RTCRtpSender.getCapabilities('video');
-  const codec = capabilities.codecs.find(c => c.mimeType === 'video/VP8');
-  assert_true(codec !== undefined);
-  transceiver.setCodecPreferences([codec]);
-  exchangeIceCandidates(pc1, pc2);
-  await exchangeOfferAnswer(pc1, pc2);
-  const sendParams = pc1.getSenders()[0].getParameters();
-  assert_not_equals(sendParams.encodings[0].scalabilityMode, 'L3T3');
-}, 'L3T3 on VP8 should return something other than L3T3');
+  promise_test(async t => {
+    const pc1 = new RTCPeerConnection();
+    const pc2 = new RTCPeerConnection();
+    t.add_cleanup(() => pc1.close());
+    t.add_cleanup(() => pc2.close());
+    const { sender } = pc1.addTransceiver('video', {
+      sendEncodings: [{}],
+    });
+    const param = sender.getParameters();
+    const encoding = getFirstEncoding(param);
 
+    exchangeIceCandidates(pc1, pc2);
+    await exchangeOfferAnswer(pc1, pc2);
+    const param2 = sender.getParameters();
+    const encoding2 = getFirstEncoding(param);
+    assert_true('scalabilityMode' in encoding2);
+  }, 'Not setting a scalability mode results in some mode set after negotiation');
 
+  promise_test(async t => {
+      const pc = new RTCPeerConnection();
+    t.add_cleanup(() => pc.close());
+    assert_throws_dom('OperationError', () => {
+      pc.addTransceiver('video', {
+        sendEncodings: [{scalabilityMode: 'TotalNonsense'}],
+      });
+    });
+  }, 'Setting a scalability mode to nonsense throws an exception');
+
+  promise_test(async t => {
+    const v = document.createElement('video');
+    v.autoplay = true;
+    const pc1 = new RTCPeerConnection();
+    const pc2 = new RTCPeerConnection();
+    t.add_cleanup(() => pc1.close());
+    t.add_cleanup(() => pc2.close());
+    const transceiver = pc1.addTransceiver('video', {
+      sendEncodings: [{ scalabilityMode: 'L3T3' }],
+    });
+    // Before negotiation, the mode should be preserved.
+    const param = transceiver.sender.getParameters();
+    const encoding = getFirstEncoding(param);
+    assert_true('scalabilityMode' in encoding);
+    // If L3T3 is not supported at all, abort test.
+    assert_implements_optional(encoding.scalabilityMode === 'L3T3');
+    // Pick a codec known to not have L3T3 support
+    const capabilities = RTCRtpSender.getCapabilities('video');
+    const codec = capabilities.codecs.find(c => c.mimeType === 'video/VP8');
+    assert_true(codec !== undefined);
+    transceiver.setCodecPreferences([codec]);
+    exchangeIceCandidates(pc1, pc2);
+    await exchangeOfferAnswer(pc1, pc2);
+    const sendParams = pc1.getSenders()[0].getParameters();
+    assert_not_equals(sendParams.encodings[0].scalabilityMode, 'L3T3');
+  }, 'L3T3 on VP8 should return something other than L3T3');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-svc/svc-helper.js b/third_party/blink/web_tests/external/wpt/webrtc-svc/svc-helper.js
new file mode 100644
index 0000000..e73ccfa7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-svc/svc-helper.js
@@ -0,0 +1,50 @@
+function supportsCodec(mimeType) {
+  return RTCRtpSender.getCapabilities('video').codecs.filter(c => c.mimeType == mimeType).length() > 0;
+}
+
+async function supportsScalabilityMode(mimeType, scalabilityMode) {
+  let result = await navigator.mediaCapabilities.encodingInfo({
+    type: 'webrtc',
+    video: {
+      contentType: mimeType,
+      width: 60,
+      height: 60,
+      bitrate: 10000,
+      framerate: 30,
+      scalabilityMode: scalabilityMode
+    }
+  });
+  return result.supported;
+}
+
+function createScalabilityTest(mimeType, scalabilityModes) {
+  for (const scalabilityMode of scalabilityModes) {
+    promise_test(async t => {
+      assert_implements_optional(
+        supportsScalabilityMode(mimeType, scalabilityMode),
+        `${mimeType} supported`
+      );
+      const v = document.createElement('video');
+      v.autoplay = true;
+      const pc1 = new RTCPeerConnection();
+      const pc2 = new RTCPeerConnection();
+      t.add_cleanup(() => pc1.close());
+      t.add_cleanup(() => pc2.close());
+      const stream1 = await getNoiseStream({ video: { signal: 100, width: 60, height: 60 } });
+      const [track1] = stream1.getTracks();
+      t.add_cleanup(() => track1.stop());
+      const transceiver = pc1.addTransceiver(track1, {
+        sendEncodings: [{ scalabilityMode: scalabilityMode }],
+      });
+      transceiver.setCodecPreferences(RTCRtpSender.getCapabilities('video').codecs.filter(c => c.mimeType == mimeType));
+      const haveTrackEvent = new Promise(r => pc2.ontrack = r);
+      exchangeIceCandidates(pc1, pc2);
+      await exchangeOfferAnswer(pc1, pc2);
+      v.srcObject = new MediaStream([(await haveTrackEvent).track]);
+      await new Promise(r => v.onloadedmetadata = r);
+      await detectSignal(t, v, 100);
+      const sendParams = pc1.getSenders()[0].getParameters();
+      assert_equals(sendParams.encodings[0].scalabilityMode, scalabilityMode);
+    }, `${mimeType} - ${scalabilityMode} should produce valid video content`);
+  }
+}
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/aria-owns-sends-notification-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/aria-owns-sends-notification-expected.txt
index f48253f9..07bd145e 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/aria-owns-sends-notification-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/accessibility/aria-owns-sends-notification-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
-PASS A children changed notification is fired when an aria-owned child gets added to the tree.
-FAIL A children changed notification is fired when an aria-owned attribute is added to an element that causes it to reparent another element to become its child. assert_equals: expected "ChildrenChanged" but got "MarkDirty"
-PASS A children changed notification is fired on the old parent when one of its children gets reparented to another element due to aria-owns.
+PASS A mark dirty notification is fired when an aria-owned child gets added to the tree.
+PASS A mark dirty notification is fired when an aria-owned attribute is added to an element that causes it to reparent another element to become its child.
+PASS A mark dirty notification is fired on the old parent when one of its children gets reparented to another element due to aria-owns.
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
deleted file mode 100644
index 18767b5..0000000
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-PASS share() is disabled by default 'self' by permissions policy for cross-origin iframes
-PASS share() is disabled explicitly by permissions policy for cross-origin iframe
-PASS share() not allowed, as only allowed to share with self
-PASS canShare() not allowed to share by default permissions policy cross-origin
-FAIL canShare() is allowed by permissions policy to share cross-origin on a particular origin assert_equals: Expected true, is it can now share on https://web-platform.test:8444. expected true but got false
-PASS canShare() with self
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
deleted file mode 100644
index 18767b5..0000000
--- a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/web-share/disabled-by-permissions-policy-cross-origin.https.sub-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-PASS share() is disabled by default 'self' by permissions policy for cross-origin iframes
-PASS share() is disabled explicitly by permissions policy for cross-origin iframe
-PASS share() not allowed, as only allowed to share with self
-PASS canShare() not allowed to share by default permissions policy cross-origin
-FAIL canShare() is allowed by permissions policy to share cross-origin on a particular origin assert_equals: Expected true, is it can now share on https://web-platform.test:8444. expected true but got false
-PASS canShare() with self
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/target/auto-attach-wait-for-debugger-2-sessions-worker-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/target/auto-attach-wait-for-debugger-2-sessions-worker-expected.txt
new file mode 100644
index 0000000..7b7cb22
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/target/auto-attach-wait-for-debugger-2-sessions-worker-expected.txt
@@ -0,0 +1,26 @@
+Tests that worker is only resumed when all sessions issue runIfWaitingForDebugger.
+Attached 2 sessions:[
+    [0] : {
+        attached : true
+        browserContextId : <string>
+        canAccessOpener : false
+        targetId : <string>
+        title : http://127.0.0.1:8000/inspector-protocol/network/resources/worker.js
+        type : worker
+        url : http://127.0.0.1:8000/inspector-protocol/network/resources/worker.js
+    }
+    [1] : {
+        attached : true
+        browserContextId : <string>
+        canAccessOpener : false
+        targetId : <string>
+        title : http://127.0.0.1:8000/inspector-protocol/network/resources/worker.js
+        type : worker
+        url : http://127.0.0.1:8000/inspector-protocol/network/resources/worker.js
+    }
+]
+Session 1 resumed!
+Session 2 resumed!
+Session 1: Worker
+Session 2: Worker
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/target/auto-attach-wait-for-debugger-2-sessions-worker.js b/third_party/blink/web_tests/http/tests/inspector-protocol/target/auto-attach-wait-for-debugger-2-sessions-worker.js
new file mode 100644
index 0000000..c01f0ab
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/target/auto-attach-wait-for-debugger-2-sessions-worker.js
@@ -0,0 +1,45 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startBlank(
+      `Tests that worker is only resumed when all sessions issue runIfWaitingForDebugger.`);
+
+  await dp.Target.setAutoAttach(
+    {autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
+
+  const dp2 = (await page.createSession()).protocol;
+
+  await dp2.Target.setAutoAttach(
+    {autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
+
+
+  session.evaluate(`
+    self.worker = new Worker('/inspector-protocol/network/resources/worker.js');
+  `);
+
+  const attached = await Promise.all([
+    dp.Target.onceAttachedToTarget(),
+    dp2.Target.onceAttachedToTarget()
+  ]);
+
+  testRunner.log(attached.map(event => event.params.targetInfo), 'Attached 2 sessions:');
+
+  const worker_session1 = (session.createChild(attached[0].params.sessionId));
+  const worker_session2 = (session.createChild(attached[1].params.sessionId));
+  const [wp1, wp2] = [worker_session1.protocol, worker_session2.protocol];
+
+  wp1.Runtime.enable();
+  wp2.Runtime.enable();
+
+  wp1.Runtime.onConsoleAPICalled(event => testRunner.log('Session 1: ' + event.params.args[0].value));
+  wp2.Runtime.onConsoleAPICalled(event => testRunner.log('Session 2: ' + event.params.args[0].value));
+
+  await wp1.Runtime.runIfWaitingForDebugger();
+  testRunner.log(`Session 1 resumed!`)
+
+  await wp1.Runtime.runIfWaitingForDebugger();
+  testRunner.log(`Session 2 resumed!`);
+
+  await worker_session1.evaluate('');
+
+  testRunner.completeTest();
+})
+
diff --git a/third_party/blink/web_tests/virtual/view-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt b/third_party/blink/web_tests/virtual/view-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
index 2f2eedd0..d3a5e1d 100644
--- a/third_party/blink/web_tests/virtual/view-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
+++ b/third_party/blink/web_tests/virtual/view-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
@@ -234,6 +234,46 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        text : html::view-transition-group()
+                                    }
+                                ]
+                                text : html::view-transition-group()
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
+                                        name : animation-duration
+                                        value : 0.25s
+                                    }
+                                    [1] : {
+                                        name : animation-fill-mode
+                                        value : both
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [2] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
+                                    [0] : {
                                         text : html::view-transition-group(root)
                                     }
                                 ]
@@ -336,28 +376,20 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
-                                        text : html::view-transition-group(shared)
+                                        text : html::view-transition-group()
                                     }
                                 ]
-                                text : html::view-transition-group(shared)
+                                text : html::view-transition-group()
                             }
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : width
-                                        value : 100px
+                                        name : animation-duration
+                                        value : 0.25s
                                     }
                                     [1] : {
-                                        name : height
-                                        value : 100px
-                                    }
-                                    [2] : {
-                                        name : transform
-                                        value : matrix(1, 0, 0, 1, 8, 8)
-                                    }
-                                    [3] : {
-                                        name : writing-mode
-                                        value : horizontal-tb
+                                        name : animation-fill-mode
+                                        value : both
                                     }
                                 ]
                                 shorthandEntries : [
@@ -392,30 +424,70 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
+                                        name : width
+                                        value : 100px
+                                    }
+                                    [1] : {
+                                        name : height
+                                        value : 100px
+                                    }
+                                    [2] : {
+                                        name : transform
+                                        value : matrix(1, 0, 0, 1, 8, 8)
+                                    }
+                                    [3] : {
+                                        name : writing-mode
+                                        value : horizontal-tb
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [3] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
+                                    [0] : {
+                                        text : html::view-transition-group(shared)
+                                    }
+                                ]
+                                text : html::view-transition-group(shared)
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
                                         name : animation-name
                                         value : -ua-view-transition-group-anim-shared
                                     }
                                     [1] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [2] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [3] : {
                                         name : animation-timing-function
                                         value : ease
                                     }
-                                    [4] : {
+                                    [2] : {
                                         name : animation-delay
                                         value : 0s
                                     }
-                                    [5] : {
+                                    [3] : {
                                         name : animation-iteration-count
                                         value : 1
                                     }
-                                    [6] : {
+                                    [4] : {
                                         name : animation-direction
                                         value : normal
                                     }
@@ -506,6 +578,46 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        text : html::view-transition-image-pair()
+                                    }
+                                ]
+                                text : html::view-transition-image-pair()
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [1] : {
+                                        name : animation-fill-mode
+                                        value : inherit
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [2] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
+                                    [0] : {
                                         text : html::view-transition-image-pair(root)
                                     }
                                 ]
@@ -604,6 +716,46 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        text : html::view-transition-image-pair()
+                                    }
+                                ]
+                                text : html::view-transition-image-pair()
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [1] : {
+                                        name : animation-fill-mode
+                                        value : inherit
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [2] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
+                                    [0] : {
                                         text : html::view-transition-image-pair(shared)
                                     }
                                 ]
@@ -709,47 +861,19 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [1] : {
-                                        name : animation-timing-function
-                                        value : ease
-                                    }
-                                    [2] : {
-                                        name : animation-delay
-                                        value : 0s
-                                    }
-                                    [3] : {
-                                        name : animation-iteration-count
-                                        value : 1
-                                    }
-                                    [4] : {
-                                        name : animation-direction
-                                        value : normal
-                                    }
-                                    [5] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [6] : {
-                                        name : animation-play-state
-                                        value : running
-                                    }
-                                    [7] : {
                                         name : animation-name
                                         value : -ua-view-transition-fade-out
                                     }
-                                    [8] : {
-                                        name : animation-timeline
-                                        value : auto
+                                    [1] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [2] : {
+                                        name : animation-fill-mode
+                                        value : inherit
                                     }
                                 ]
                                 shorthandEntries : [
-                                    [0] : {
-                                        name : animation
-                                        value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-out
-                                    }
                                 ]
                             }
                             supports : [
@@ -1024,47 +1148,19 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [1] : {
-                                        name : animation-timing-function
-                                        value : ease
-                                    }
-                                    [2] : {
-                                        name : animation-delay
-                                        value : 0s
-                                    }
-                                    [3] : {
-                                        name : animation-iteration-count
-                                        value : 1
-                                    }
-                                    [4] : {
-                                        name : animation-direction
-                                        value : normal
-                                    }
-                                    [5] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [6] : {
-                                        name : animation-play-state
-                                        value : running
-                                    }
-                                    [7] : {
                                         name : animation-name
                                         value : -ua-view-transition-fade-out
                                     }
-                                    [8] : {
-                                        name : animation-timeline
-                                        value : auto
+                                    [1] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [2] : {
+                                        name : animation-fill-mode
+                                        value : inherit
                                     }
                                 ]
                                 shorthandEntries : [
-                                    [0] : {
-                                        name : animation
-                                        value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-out
-                                    }
                                 ]
                             }
                             supports : [
@@ -1339,47 +1435,19 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [1] : {
-                                        name : animation-timing-function
-                                        value : ease
-                                    }
-                                    [2] : {
-                                        name : animation-delay
-                                        value : 0s
-                                    }
-                                    [3] : {
-                                        name : animation-iteration-count
-                                        value : 1
-                                    }
-                                    [4] : {
-                                        name : animation-direction
-                                        value : normal
-                                    }
-                                    [5] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [6] : {
-                                        name : animation-play-state
-                                        value : running
-                                    }
-                                    [7] : {
                                         name : animation-name
                                         value : -ua-view-transition-fade-in
                                     }
-                                    [8] : {
-                                        name : animation-timeline
-                                        value : auto
+                                    [1] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [2] : {
+                                        name : animation-fill-mode
+                                        value : inherit
                                     }
                                 ]
                                 shorthandEntries : [
-                                    [0] : {
-                                        name : animation
-                                        value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-in
-                                    }
                                 ]
                             }
                             supports : [
@@ -1508,47 +1576,19 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [1] : {
-                                        name : animation-timing-function
-                                        value : ease
-                                    }
-                                    [2] : {
-                                        name : animation-delay
-                                        value : 0s
-                                    }
-                                    [3] : {
-                                        name : animation-iteration-count
-                                        value : 1
-                                    }
-                                    [4] : {
-                                        name : animation-direction
-                                        value : normal
-                                    }
-                                    [5] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [6] : {
-                                        name : animation-play-state
-                                        value : running
-                                    }
-                                    [7] : {
                                         name : animation-name
                                         value : -ua-view-transition-fade-in
                                     }
-                                    [8] : {
-                                        name : animation-timeline
-                                        value : auto
+                                    [1] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [2] : {
+                                        name : animation-fill-mode
+                                        value : inherit
                                     }
                                 ]
                                 shorthandEntries : [
-                                    [0] : {
-                                        name : animation
-                                        value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-in
-                                    }
                                 ]
                             }
                             supports : [
@@ -1840,6 +1880,46 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                text : html::view-transition-group()
+                            }
+                        ]
+                        text : html::view-transition-group()
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
+                                name : animation-duration
+                                value : 0.25s
+                            }
+                            [1] : {
+                                name : animation-fill-mode
+                                value : both
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [2] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
+                            [0] : {
                                 text : html::view-transition-group(root)
                             }
                         ]
@@ -1946,6 +2026,46 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                text : html::view-transition-image-pair()
+                            }
+                        ]
+                        text : html::view-transition-image-pair()
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [1] : {
+                                name : animation-fill-mode
+                                value : inherit
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [2] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
+                            [0] : {
                                 text : html::view-transition-image-pair(root)
                             }
                         ]
@@ -2055,47 +2175,19 @@
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [1] : {
-                                name : animation-timing-function
-                                value : ease
-                            }
-                            [2] : {
-                                name : animation-delay
-                                value : 0s
-                            }
-                            [3] : {
-                                name : animation-iteration-count
-                                value : 1
-                            }
-                            [4] : {
-                                name : animation-direction
-                                value : normal
-                            }
-                            [5] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [6] : {
-                                name : animation-play-state
-                                value : running
-                            }
-                            [7] : {
                                 name : animation-name
                                 value : -ua-view-transition-fade-out
                             }
-                            [8] : {
-                                name : animation-timeline
-                                value : auto
+                            [1] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [2] : {
+                                name : animation-fill-mode
+                                value : inherit
                             }
                         ]
                         shorthandEntries : [
-                            [0] : {
-                                name : animation
-                                value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-out
-                            }
                         ]
                     }
                     supports : [
@@ -2374,47 +2466,19 @@
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [1] : {
-                                name : animation-timing-function
-                                value : ease
-                            }
-                            [2] : {
-                                name : animation-delay
-                                value : 0s
-                            }
-                            [3] : {
-                                name : animation-iteration-count
-                                value : 1
-                            }
-                            [4] : {
-                                name : animation-direction
-                                value : normal
-                            }
-                            [5] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [6] : {
-                                name : animation-play-state
-                                value : running
-                            }
-                            [7] : {
                                 name : animation-name
                                 value : -ua-view-transition-fade-in
                             }
-                            [8] : {
-                                name : animation-timeline
-                                value : auto
+                            [1] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [2] : {
+                                name : animation-fill-mode
+                                value : inherit
                             }
                         ]
                         shorthandEntries : [
-                            [0] : {
-                                name : animation
-                                value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-in
-                            }
                         ]
                     }
                     supports : [
@@ -2540,28 +2604,20 @@
                     selectorList : {
                         selectors : [
                             [0] : {
-                                text : html::view-transition-group(shared)
+                                text : html::view-transition-group()
                             }
                         ]
-                        text : html::view-transition-group(shared)
+                        text : html::view-transition-group()
                     }
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : width
-                                value : 100px
+                                name : animation-duration
+                                value : 0.25s
                             }
                             [1] : {
-                                name : height
-                                value : 100px
-                            }
-                            [2] : {
-                                name : transform
-                                value : matrix(1, 0, 0, 1, 8, 8)
-                            }
-                            [3] : {
-                                name : writing-mode
-                                value : horizontal-tb
+                                name : animation-fill-mode
+                                value : both
                             }
                         ]
                         shorthandEntries : [
@@ -2596,30 +2652,70 @@
                     style : {
                         cssProperties : [
                             [0] : {
+                                name : width
+                                value : 100px
+                            }
+                            [1] : {
+                                name : height
+                                value : 100px
+                            }
+                            [2] : {
+                                name : transform
+                                value : matrix(1, 0, 0, 1, 8, 8)
+                            }
+                            [3] : {
+                                name : writing-mode
+                                value : horizontal-tb
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [3] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
+                            [0] : {
+                                text : html::view-transition-group(shared)
+                            }
+                        ]
+                        text : html::view-transition-group(shared)
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
                                 name : animation-name
                                 value : -ua-view-transition-group-anim-shared
                             }
                             [1] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [2] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [3] : {
                                 name : animation-timing-function
                                 value : ease
                             }
-                            [4] : {
+                            [2] : {
                                 name : animation-delay
                                 value : 0s
                             }
-                            [5] : {
+                            [3] : {
                                 name : animation-iteration-count
                                 value : 1
                             }
-                            [6] : {
+                            [4] : {
                                 name : animation-direction
                                 value : normal
                             }
@@ -2714,6 +2810,46 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                text : html::view-transition-image-pair()
+                            }
+                        ]
+                        text : html::view-transition-image-pair()
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [1] : {
+                                name : animation-fill-mode
+                                value : inherit
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [2] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
+                            [0] : {
                                 text : html::view-transition-image-pair(shared)
                             }
                         ]
@@ -2823,47 +2959,19 @@
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [1] : {
-                                name : animation-timing-function
-                                value : ease
-                            }
-                            [2] : {
-                                name : animation-delay
-                                value : 0s
-                            }
-                            [3] : {
-                                name : animation-iteration-count
-                                value : 1
-                            }
-                            [4] : {
-                                name : animation-direction
-                                value : normal
-                            }
-                            [5] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [6] : {
-                                name : animation-play-state
-                                value : running
-                            }
-                            [7] : {
                                 name : animation-name
                                 value : -ua-view-transition-fade-out
                             }
-                            [8] : {
-                                name : animation-timeline
-                                value : auto
+                            [1] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [2] : {
+                                name : animation-fill-mode
+                                value : inherit
                             }
                         ]
                         shorthandEntries : [
-                            [0] : {
-                                name : animation
-                                value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-out
-                            }
                         ]
                     }
                     supports : [
@@ -3142,47 +3250,19 @@
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [1] : {
-                                name : animation-timing-function
-                                value : ease
-                            }
-                            [2] : {
-                                name : animation-delay
-                                value : 0s
-                            }
-                            [3] : {
-                                name : animation-iteration-count
-                                value : 1
-                            }
-                            [4] : {
-                                name : animation-direction
-                                value : normal
-                            }
-                            [5] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [6] : {
-                                name : animation-play-state
-                                value : running
-                            }
-                            [7] : {
                                 name : animation-name
                                 value : -ua-view-transition-fade-in
                             }
-                            [8] : {
-                                name : animation-timeline
-                                value : auto
+                            [1] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [2] : {
+                                name : animation-fill-mode
+                                value : inherit
                             }
                         ]
                         shorthandEntries : [
-                            [0] : {
-                                name : animation
-                                value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-in
-                            }
                         ]
                     }
                     supports : [
diff --git a/third_party/blink/web_tests/virtual/view-transition/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt b/third_party/blink/web_tests/virtual/view-transition/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
index 2f2eedd0..d3a5e1d 100644
--- a/third_party/blink/web_tests/virtual/view-transition/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
+++ b/third_party/blink/web_tests/virtual/view-transition/inspector-protocol/css/css-get-styles-for-view-transition-expected.txt
@@ -234,6 +234,46 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        text : html::view-transition-group()
+                                    }
+                                ]
+                                text : html::view-transition-group()
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
+                                        name : animation-duration
+                                        value : 0.25s
+                                    }
+                                    [1] : {
+                                        name : animation-fill-mode
+                                        value : both
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [2] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
+                                    [0] : {
                                         text : html::view-transition-group(root)
                                     }
                                 ]
@@ -336,28 +376,20 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
-                                        text : html::view-transition-group(shared)
+                                        text : html::view-transition-group()
                                     }
                                 ]
-                                text : html::view-transition-group(shared)
+                                text : html::view-transition-group()
                             }
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : width
-                                        value : 100px
+                                        name : animation-duration
+                                        value : 0.25s
                                     }
                                     [1] : {
-                                        name : height
-                                        value : 100px
-                                    }
-                                    [2] : {
-                                        name : transform
-                                        value : matrix(1, 0, 0, 1, 8, 8)
-                                    }
-                                    [3] : {
-                                        name : writing-mode
-                                        value : horizontal-tb
+                                        name : animation-fill-mode
+                                        value : both
                                     }
                                 ]
                                 shorthandEntries : [
@@ -392,30 +424,70 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
+                                        name : width
+                                        value : 100px
+                                    }
+                                    [1] : {
+                                        name : height
+                                        value : 100px
+                                    }
+                                    [2] : {
+                                        name : transform
+                                        value : matrix(1, 0, 0, 1, 8, 8)
+                                    }
+                                    [3] : {
+                                        name : writing-mode
+                                        value : horizontal-tb
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [3] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
+                                    [0] : {
+                                        text : html::view-transition-group(shared)
+                                    }
+                                ]
+                                text : html::view-transition-group(shared)
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
                                         name : animation-name
                                         value : -ua-view-transition-group-anim-shared
                                     }
                                     [1] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [2] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [3] : {
                                         name : animation-timing-function
                                         value : ease
                                     }
-                                    [4] : {
+                                    [2] : {
                                         name : animation-delay
                                         value : 0s
                                     }
-                                    [5] : {
+                                    [3] : {
                                         name : animation-iteration-count
                                         value : 1
                                     }
-                                    [6] : {
+                                    [4] : {
                                         name : animation-direction
                                         value : normal
                                     }
@@ -506,6 +578,46 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        text : html::view-transition-image-pair()
+                                    }
+                                ]
+                                text : html::view-transition-image-pair()
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [1] : {
+                                        name : animation-fill-mode
+                                        value : inherit
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [2] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
+                                    [0] : {
                                         text : html::view-transition-image-pair(root)
                                     }
                                 ]
@@ -604,6 +716,46 @@
                             selectorList : {
                                 selectors : [
                                     [0] : {
+                                        text : html::view-transition-image-pair()
+                                    }
+                                ]
+                                text : html::view-transition-image-pair()
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [1] : {
+                                        name : animation-fill-mode
+                                        value : inherit
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [2] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
+                                    [0] : {
                                         text : html::view-transition-image-pair(shared)
                                     }
                                 ]
@@ -709,47 +861,19 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [1] : {
-                                        name : animation-timing-function
-                                        value : ease
-                                    }
-                                    [2] : {
-                                        name : animation-delay
-                                        value : 0s
-                                    }
-                                    [3] : {
-                                        name : animation-iteration-count
-                                        value : 1
-                                    }
-                                    [4] : {
-                                        name : animation-direction
-                                        value : normal
-                                    }
-                                    [5] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [6] : {
-                                        name : animation-play-state
-                                        value : running
-                                    }
-                                    [7] : {
                                         name : animation-name
                                         value : -ua-view-transition-fade-out
                                     }
-                                    [8] : {
-                                        name : animation-timeline
-                                        value : auto
+                                    [1] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [2] : {
+                                        name : animation-fill-mode
+                                        value : inherit
                                     }
                                 ]
                                 shorthandEntries : [
-                                    [0] : {
-                                        name : animation
-                                        value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-out
-                                    }
                                 ]
                             }
                             supports : [
@@ -1024,47 +1148,19 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [1] : {
-                                        name : animation-timing-function
-                                        value : ease
-                                    }
-                                    [2] : {
-                                        name : animation-delay
-                                        value : 0s
-                                    }
-                                    [3] : {
-                                        name : animation-iteration-count
-                                        value : 1
-                                    }
-                                    [4] : {
-                                        name : animation-direction
-                                        value : normal
-                                    }
-                                    [5] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [6] : {
-                                        name : animation-play-state
-                                        value : running
-                                    }
-                                    [7] : {
                                         name : animation-name
                                         value : -ua-view-transition-fade-out
                                     }
-                                    [8] : {
-                                        name : animation-timeline
-                                        value : auto
+                                    [1] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [2] : {
+                                        name : animation-fill-mode
+                                        value : inherit
                                     }
                                 ]
                                 shorthandEntries : [
-                                    [0] : {
-                                        name : animation
-                                        value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-out
-                                    }
                                 ]
                             }
                             supports : [
@@ -1339,47 +1435,19 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [1] : {
-                                        name : animation-timing-function
-                                        value : ease
-                                    }
-                                    [2] : {
-                                        name : animation-delay
-                                        value : 0s
-                                    }
-                                    [3] : {
-                                        name : animation-iteration-count
-                                        value : 1
-                                    }
-                                    [4] : {
-                                        name : animation-direction
-                                        value : normal
-                                    }
-                                    [5] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [6] : {
-                                        name : animation-play-state
-                                        value : running
-                                    }
-                                    [7] : {
                                         name : animation-name
                                         value : -ua-view-transition-fade-in
                                     }
-                                    [8] : {
-                                        name : animation-timeline
-                                        value : auto
+                                    [1] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [2] : {
+                                        name : animation-fill-mode
+                                        value : inherit
                                     }
                                 ]
                                 shorthandEntries : [
-                                    [0] : {
-                                        name : animation
-                                        value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-in
-                                    }
                                 ]
                             }
                             supports : [
@@ -1508,47 +1576,19 @@
                             style : {
                                 cssProperties : [
                                     [0] : {
-                                        name : animation-duration
-                                        value : 0.25s
-                                    }
-                                    [1] : {
-                                        name : animation-timing-function
-                                        value : ease
-                                    }
-                                    [2] : {
-                                        name : animation-delay
-                                        value : 0s
-                                    }
-                                    [3] : {
-                                        name : animation-iteration-count
-                                        value : 1
-                                    }
-                                    [4] : {
-                                        name : animation-direction
-                                        value : normal
-                                    }
-                                    [5] : {
-                                        name : animation-fill-mode
-                                        value : both
-                                    }
-                                    [6] : {
-                                        name : animation-play-state
-                                        value : running
-                                    }
-                                    [7] : {
                                         name : animation-name
                                         value : -ua-view-transition-fade-in
                                     }
-                                    [8] : {
-                                        name : animation-timeline
-                                        value : auto
+                                    [1] : {
+                                        name : animation-duration
+                                        value : inherit
+                                    }
+                                    [2] : {
+                                        name : animation-fill-mode
+                                        value : inherit
                                     }
                                 ]
                                 shorthandEntries : [
-                                    [0] : {
-                                        name : animation
-                                        value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-in
-                                    }
                                 ]
                             }
                             supports : [
@@ -1840,6 +1880,46 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                text : html::view-transition-group()
+                            }
+                        ]
+                        text : html::view-transition-group()
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
+                                name : animation-duration
+                                value : 0.25s
+                            }
+                            [1] : {
+                                name : animation-fill-mode
+                                value : both
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [2] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
+                            [0] : {
                                 text : html::view-transition-group(root)
                             }
                         ]
@@ -1946,6 +2026,46 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                text : html::view-transition-image-pair()
+                            }
+                        ]
+                        text : html::view-transition-image-pair()
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [1] : {
+                                name : animation-fill-mode
+                                value : inherit
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [2] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
+                            [0] : {
                                 text : html::view-transition-image-pair(root)
                             }
                         ]
@@ -2055,47 +2175,19 @@
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [1] : {
-                                name : animation-timing-function
-                                value : ease
-                            }
-                            [2] : {
-                                name : animation-delay
-                                value : 0s
-                            }
-                            [3] : {
-                                name : animation-iteration-count
-                                value : 1
-                            }
-                            [4] : {
-                                name : animation-direction
-                                value : normal
-                            }
-                            [5] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [6] : {
-                                name : animation-play-state
-                                value : running
-                            }
-                            [7] : {
                                 name : animation-name
                                 value : -ua-view-transition-fade-out
                             }
-                            [8] : {
-                                name : animation-timeline
-                                value : auto
+                            [1] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [2] : {
+                                name : animation-fill-mode
+                                value : inherit
                             }
                         ]
                         shorthandEntries : [
-                            [0] : {
-                                name : animation
-                                value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-out
-                            }
                         ]
                     }
                     supports : [
@@ -2374,47 +2466,19 @@
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [1] : {
-                                name : animation-timing-function
-                                value : ease
-                            }
-                            [2] : {
-                                name : animation-delay
-                                value : 0s
-                            }
-                            [3] : {
-                                name : animation-iteration-count
-                                value : 1
-                            }
-                            [4] : {
-                                name : animation-direction
-                                value : normal
-                            }
-                            [5] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [6] : {
-                                name : animation-play-state
-                                value : running
-                            }
-                            [7] : {
                                 name : animation-name
                                 value : -ua-view-transition-fade-in
                             }
-                            [8] : {
-                                name : animation-timeline
-                                value : auto
+                            [1] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [2] : {
+                                name : animation-fill-mode
+                                value : inherit
                             }
                         ]
                         shorthandEntries : [
-                            [0] : {
-                                name : animation
-                                value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-in
-                            }
                         ]
                     }
                     supports : [
@@ -2540,28 +2604,20 @@
                     selectorList : {
                         selectors : [
                             [0] : {
-                                text : html::view-transition-group(shared)
+                                text : html::view-transition-group()
                             }
                         ]
-                        text : html::view-transition-group(shared)
+                        text : html::view-transition-group()
                     }
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : width
-                                value : 100px
+                                name : animation-duration
+                                value : 0.25s
                             }
                             [1] : {
-                                name : height
-                                value : 100px
-                            }
-                            [2] : {
-                                name : transform
-                                value : matrix(1, 0, 0, 1, 8, 8)
-                            }
-                            [3] : {
-                                name : writing-mode
-                                value : horizontal-tb
+                                name : animation-fill-mode
+                                value : both
                             }
                         ]
                         shorthandEntries : [
@@ -2596,30 +2652,70 @@
                     style : {
                         cssProperties : [
                             [0] : {
+                                name : width
+                                value : 100px
+                            }
+                            [1] : {
+                                name : height
+                                value : 100px
+                            }
+                            [2] : {
+                                name : transform
+                                value : matrix(1, 0, 0, 1, 8, 8)
+                            }
+                            [3] : {
+                                name : writing-mode
+                                value : horizontal-tb
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [3] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
+                            [0] : {
+                                text : html::view-transition-group(shared)
+                            }
+                        ]
+                        text : html::view-transition-group(shared)
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
                                 name : animation-name
                                 value : -ua-view-transition-group-anim-shared
                             }
                             [1] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [2] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [3] : {
                                 name : animation-timing-function
                                 value : ease
                             }
-                            [4] : {
+                            [2] : {
                                 name : animation-delay
                                 value : 0s
                             }
-                            [5] : {
+                            [3] : {
                                 name : animation-iteration-count
                                 value : 1
                             }
-                            [6] : {
+                            [4] : {
                                 name : animation-direction
                                 value : normal
                             }
@@ -2714,6 +2810,46 @@
                     selectorList : {
                         selectors : [
                             [0] : {
+                                text : html::view-transition-image-pair()
+                            }
+                        ]
+                        text : html::view-transition-image-pair()
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [1] : {
+                                name : animation-fill-mode
+                                value : inherit
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [2] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
+                            [0] : {
                                 text : html::view-transition-image-pair(shared)
                             }
                         ]
@@ -2823,47 +2959,19 @@
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [1] : {
-                                name : animation-timing-function
-                                value : ease
-                            }
-                            [2] : {
-                                name : animation-delay
-                                value : 0s
-                            }
-                            [3] : {
-                                name : animation-iteration-count
-                                value : 1
-                            }
-                            [4] : {
-                                name : animation-direction
-                                value : normal
-                            }
-                            [5] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [6] : {
-                                name : animation-play-state
-                                value : running
-                            }
-                            [7] : {
                                 name : animation-name
                                 value : -ua-view-transition-fade-out
                             }
-                            [8] : {
-                                name : animation-timeline
-                                value : auto
+                            [1] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [2] : {
+                                name : animation-fill-mode
+                                value : inherit
                             }
                         ]
                         shorthandEntries : [
-                            [0] : {
-                                name : animation
-                                value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-out
-                            }
                         ]
                     }
                     supports : [
@@ -3142,47 +3250,19 @@
                     style : {
                         cssProperties : [
                             [0] : {
-                                name : animation-duration
-                                value : 0.25s
-                            }
-                            [1] : {
-                                name : animation-timing-function
-                                value : ease
-                            }
-                            [2] : {
-                                name : animation-delay
-                                value : 0s
-                            }
-                            [3] : {
-                                name : animation-iteration-count
-                                value : 1
-                            }
-                            [4] : {
-                                name : animation-direction
-                                value : normal
-                            }
-                            [5] : {
-                                name : animation-fill-mode
-                                value : both
-                            }
-                            [6] : {
-                                name : animation-play-state
-                                value : running
-                            }
-                            [7] : {
                                 name : animation-name
                                 value : -ua-view-transition-fade-in
                             }
-                            [8] : {
-                                name : animation-timeline
-                                value : auto
+                            [1] : {
+                                name : animation-duration
+                                value : inherit
+                            }
+                            [2] : {
+                                name : animation-fill-mode
+                                value : inherit
                             }
                         ]
                         shorthandEntries : [
-                            [0] : {
-                                name : animation
-                                value : 0.25s ease 0s 1 normal both running -ua-view-transition-fade-in
-                            }
                         ]
                     }
                     supports : [
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js
index 3b21498e..12e3923 100644
--- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js
+++ b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js
@@ -11,6 +11,7 @@
       t.add_cleanup(() => resetAttributionReports(aggregatableReportsUrl));
       t.add_cleanup(() => resetAttributionReports(eventLevelDebugReportsUrl));
       t.add_cleanup(() => resetAttributionReports(aggregatableDebugReportsUrl));
+      t.add_cleanup(() => resetAttributionReports(verboseDebugReportsUrl));
       return f(t);
     }, name);
 
@@ -22,6 +23,8 @@
     '/.well-known/attribution-reporting/report-aggregate-attribution';
 const aggregatableDebugReportsUrl =
     '/.well-known/attribution-reporting/debug/report-aggregate-attribution';
+const verboseDebugReportsUrl =
+    '/.well-known/attribution-reporting/debug/verbose';
 
 /**
  * Method to clear the stash. Takes the URL as parameter. This could be for
@@ -225,6 +228,8 @@
     pollAttributionReports(aggregatableReportsUrl, interval);
 const pollAggregatableDebugReports = interval =>
     pollAttributionReports(aggregatableDebugReportsUrl, interval);
+const pollVerboseDebugReports = interval =>
+    pollAttributionReports(verboseDebugReportsUrl, interval);
 
 const validateReportHeaders = headers => {
   assert_array_equals(headers['content-type'], ['application/json']);
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-verbose-debug-report.sub.https.html b/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-verbose-debug-report.sub.https.html
new file mode 100644
index 0000000..1cda812
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-verbose-debug-report.sub.https.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/helpers.js"></script>
+<script>
+attribution_reporting_promise_test(async t => {
+  const cookie = 'ar_debug=1;Secure;HttpOnly;SameSite=None;Path=/';
+  await registerAttributionSrc(t, {
+    trigger: {
+      debug_reporting: true,
+    },
+    cookie,
+  });
+
+  const payload = await pollVerboseDebugReports();
+  assert_equals(payload.reports.length, 1);
+  const report = JSON.parse(payload.reports[0].body);
+  assert_equals(report.length, 1);
+  assert_equals(report[0].type, 'trigger-no-matching-source');
+  assert_own_property(report[0], 'body');
+  assert_equals(report[0].body.attribution_destination, `https://{{host}}`);
+}, 'Verbose debug report is received.');
+</script>
diff --git a/third_party/expat/README.chromium b/third_party/expat/README.chromium
index 190f65a9..798de6f0 100644
--- a/third_party/expat/README.chromium
+++ b/third_party/expat/README.chromium
@@ -1,10 +1,10 @@
 Name: Expat XML Parser
 Short Name: expat
 URL: https://github.com/libexpat/libexpat
-Version: R_2_4_7-4-g53fbdf5b
-CPEPrefix: cpe:/a:libexpat:expat:2.4.7
-Date: 20220309
-Revision: 53fbdf5b8925a426e1b41a9e09b833986b87524e
+Version: R_2_5_0-24-g441f98d0
+CPEPrefix: cpe:/a:libexpat:expat:2.5.0
+Date: 20221122
+Revision: 441f98d02deafd9b090aea568282b28f66a50e36
 Security Critical: yes
 License: MIT
 License File: src/expat/COPYING
diff --git a/third_party/expat/include/expat_config/expat_config.h b/third_party/expat/include/expat_config/expat_config.h
index 07ae928..b2c89c6b 100644
--- a/third_party/expat/include/expat_config/expat_config.h
+++ b/third_party/expat/include/expat_config/expat_config.h
@@ -1,6 +1,9 @@
 /* expat_config.h.  Generated from expat_config.h.in by configure.  */
 /* expat_config.h.in.  Generated from configure.ac by autoheader.  */
 
+#ifndef EXPAT_CONFIG_H
+#define EXPAT_CONFIG_H 1
+
 /* Define if building universal (internal helper macro) */
 /* #undef AC_APPLE_UNIVERSAL_BUILD */
 
@@ -77,7 +80,7 @@
 #define PACKAGE_NAME "expat"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "expat 2.4.7"
+#define PACKAGE_STRING "expat 2.5.0"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "expat"
@@ -86,7 +89,7 @@
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "2.4.7"
+#define PACKAGE_VERSION "2.5.0"
 
 /* Define to 1 if all of the C90 standard headers exist (not just the ones
    required in a freestanding environment). This macro is provided for
@@ -94,7 +97,7 @@
 #define STDC_HEADERS 1
 
 /* Version number of package */
-#define VERSION "2.4.7"
+#define VERSION "2.5.0"
 
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
    significant byte first (like Motorola and SPARC, unlike Intel). */
@@ -133,3 +136,5 @@
 
 /* Define to `unsigned int' if <sys/types.h> does not define. */
 /* #undef size_t */
+
+#endif // ndef EXPAT_CONFIG_H
diff --git a/tools/android/checkstyle/.style.yapf b/tools/android/checkstyle/.style.yapf
new file mode 100644
index 0000000..557fa7b
--- /dev/null
+++ b/tools/android/checkstyle/.style.yapf
@@ -0,0 +1,2 @@
+[style]
+based_on_style = pep8
diff --git a/tools/android/checkstyle/checkstyle.py b/tools/android/checkstyle/checkstyle.py
index 3224e588..59927a8 100644
--- a/tools/android/checkstyle/checkstyle.py
+++ b/tools/android/checkstyle/checkstyle.py
@@ -4,84 +4,104 @@
 
 """Script that is used by PRESUBMIT.py to run style checks on Java files."""
 
+import collections
 import os
 import subprocess
 import sys
 import xml.dom.minidom
 
 
-CHROMIUM_SRC = os.path.normpath(
-    os.path.join(os.path.dirname(__file__),
-                 os.pardir, os.pardir, os.pardir))
-CHECKSTYLE_ROOT = os.path.join(CHROMIUM_SRC, 'third_party', 'checkstyle',
-                               'checkstyle-all.jar')
-JAVA_PATH = os.path.join(CHROMIUM_SRC, 'third_party', 'jdk', 'current', 'bin',
-                         'java')
+_SELF_DIR = os.path.dirname(__file__)
+CHROMIUM_SRC = os.path.normpath(os.path.join(_SELF_DIR, '..', '..', '..'))
+_CHECKSTYLE_ROOT = os.path.join(CHROMIUM_SRC, 'third_party', 'checkstyle',
+                                'checkstyle-all.jar')
+_JAVA_PATH = os.path.join(CHROMIUM_SRC, 'third_party', 'jdk', 'current', 'bin',
+                          'java')
+_STYLE_FILE = os.path.join(_SELF_DIR, 'chromium-style-5.0.xml')
+_REMOVE_UNUSED_IMPORTS_PATH = os.path.join(_SELF_DIR,
+                                           'remove_unused_imports.py')
 
 
-def FormatCheckstyleOutput(checkstyle_output):
-  lines = checkstyle_output.splitlines(True)
-  if 'Checkstyle ends with' in lines[-1]:
-    return ''.join(lines[:-1])
-  else:
-    return checkstyle_output
+class Violation(
+        collections.namedtuple('Violation',
+                               'file,line,column,message,severity')):
+    def __str__(self):
+        column = f'{self.column}:' if self.column else ''
+        return f'{self.file}:{self.line}:{column} {self.message}'
+
+    def is_warning(self):
+        return self.severity == 'warning'
+
+    def is_error(self):
+        return self.severity == 'error'
 
 
-def RunCheckstyle(input_api, output_api, style_file, files_to_skip=None):
-  # Android toolchain is only available on Linux.
-  if not sys.platform.startswith('linux'):
-    return []
+def run_checkstyle(local_path, style_file, java_files):
+    cmd = [
+        _JAVA_PATH, '-cp', _CHECKSTYLE_ROOT,
+        'com.puppycrawl.tools.checkstyle.Main', '-c', style_file, '-f', 'xml'
+    ] + java_files
+    check = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+    stdout = check.communicate()[0].decode('utf-8')
+    results = []
 
-  if not os.path.exists(style_file):
-    file_error = ('  Java checkstyle configuration file is missing: '
-                  + style_file)
-    return [output_api.PresubmitError(file_error)]
+    lines = stdout.splitlines(keepends=True)
+    if 'Checkstyle ends with' in lines[-1]:
+        stdout = ''.join(lines[:-1])
+    try:
+        root = xml.dom.minidom.parseString(stdout)
+    except Exception:
+        print('Tried to parse:')
+        print(stdout)
+        raise
 
-  # Filter out non-Java files and files that were deleted.
-  java_files = [
-      x.AbsoluteLocalPath() for x in input_api.AffectedSourceFiles(
-          lambda f: input_api.FilterSourceFile(f, files_to_skip=files_to_skip))
-      if os.path.splitext(x.LocalPath())[1] == '.java'
-  ]
-  if not java_files:
-    return []
+    for fileElement in root.getElementsByTagName('file'):
+        filename = fileElement.attributes['name'].value
+        if filename.startswith(local_path):
+            filename = filename[len(local_path) + 1:]
+        errors = fileElement.getElementsByTagName('error')
+        for error in errors:
+            severity = error.attributes['severity'].value
+            if severity not in ('warning', 'error'):
+                continue
+            message = error.attributes['message'].value
+            line = int(error.attributes['line'].value)
+            column = None
+            if error.hasAttribute('column'):
+                column = int(error.attributes['column'].value)
+            results.append(Violation(filename, line, column, message,
+                                     severity))
+    return results
 
-  # Run checkstyle
-  check = subprocess.Popen([JAVA_PATH, '-cp',
-                            CHECKSTYLE_ROOT,
-                            'com.puppycrawl.tools.checkstyle.Main', '-c',
-                            style_file, '-f', 'xml'] + java_files,
-                            stdout=subprocess.PIPE)
-  stdout = check.communicate()[0].decode('utf-8')
 
-  result_errors = []
-  result_warnings = []
+def run_presubmit(input_api, output_api, files_to_skip=None):
+    # Android toolchain is only available on Linux.
+    if not sys.platform.startswith('linux'):
+        return []
 
-  formatted_checkstyle_output = FormatCheckstyleOutput(stdout)
+    # Filter out non-Java files and files that were deleted.
+    java_files = [
+        x.AbsoluteLocalPath() for x in
+        input_api.AffectedSourceFiles(lambda f: input_api.FilterSourceFile(
+            f, files_to_skip=files_to_skip)) if x.LocalPath().endswith('.java')
+    ]
+    if not java_files:
+        return []
 
-  local_path = input_api.PresubmitLocalPath()
-  root = xml.dom.minidom.parseString(formatted_checkstyle_output)
-  for fileElement in root.getElementsByTagName('file'):
-    fileName = fileElement.attributes['name'].value
-    fileName = os.path.relpath(fileName, local_path)
-    errors = fileElement.getElementsByTagName('error')
-    for error in errors:
-      line = error.attributes['line'].value
-      column = ''
-      if error.hasAttribute('column'):
-        column = '%s:' % (error.attributes['column'].value)
-      message = error.attributes['message'].value
-      result = '  %s:%s:%s %s' % (fileName, line, column, message)
+    local_path = input_api.PresubmitLocalPath()
+    violations = run_checkstyle(local_path, _STYLE_FILE, java_files)
+    warnings = ['  ' + str(v) for v in violations if v.is_warning()]
+    errors = ['  ' + str(v) for v in violations if v.is_error()]
 
-      severity = error.attributes['severity'].value
-      if severity == 'error':
-        result_errors.append(result)
-      elif severity == 'warning':
-        result_warnings.append(result)
+    ret = []
+    if warnings:
+        ret.append(output_api.PresubmitPromptWarning('\n'.join(warnings)))
+    if errors:
+        msg = '\n'.join(errors)
+        if 'Unused import:' in msg or 'Duplicate import' in msg:
+            msg += """
 
-  result = []
-  if result_warnings:
-    result.append(output_api.PresubmitPromptWarning('\n'.join(result_warnings)))
-  if result_errors:
-    result.append(output_api.PresubmitError('\n'.join(result_errors)))
-  return result
+To remove unused imports: """ + input_api.os_path.relpath(
+                _REMOVE_UNUSED_IMPORTS_PATH, local_path)
+        ret.append(output_api.PresubmitError(msg))
+    return ret
diff --git a/tools/android/checkstyle/remove_unused_imports.py b/tools/android/checkstyle/remove_unused_imports.py
new file mode 100755
index 0000000..0484f09
--- /dev/null
+++ b/tools/android/checkstyle/remove_unused_imports.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+# 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.
+"""Uses checkstyle to find unused imports and then removes them."""
+
+import os
+import pathlib
+import subprocess
+import sys
+
+import checkstyle
+
+_STYLE_FILE = os.path.join(os.path.dirname(__file__), 'unused-imports.xml')
+
+
+def _query_for_java_files():
+    git_root = subprocess.check_output('git rev-parse --show-toplevel',
+                                       shell=True,
+                                       encoding='utf8').strip()
+    result = subprocess.run(
+        ('git diff --name-only -M '
+         '$(git merge-base @{u} HEAD 2>/dev/null || echo HEAD^)'),
+        capture_output=True,
+        check=True,
+        shell=True,
+        encoding='utf8')
+    paths = (os.path.join(git_root, x) for x in result.stdout.splitlines()
+             if x.endswith('.java'))
+    return [p for p in paths if os.path.exists(p)]
+
+
+def _delete_line(path, line):
+    lines = path.read_text().splitlines(keepends=True)
+    lines.pop(line - 1)
+    # Check if removed last import from an import group.
+    if lines[line - 2:line] == ['\n', '\n']:
+        lines.pop(line - 1)
+
+    path.write_text(''.join(lines))
+
+
+def main():
+    java_files = _query_for_java_files()
+    if not java_files:
+        print('There are no changed .java files.')
+        sys.exit(1)
+    os.chdir(checkstyle.CHROMIUM_SRC)
+    violations = checkstyle.run_checkstyle(checkstyle.CHROMIUM_SRC,
+                                           _STYLE_FILE, java_files)
+    processed = set()
+    for v in sorted(violations, key=lambda x: -x.line):
+        # Guard against multiple warnings on the same line.
+        key = (v.file, v.line)
+        if key not in processed:
+            _delete_line(pathlib.Path(v.file), v.line)
+            processed.add(key)
+    count = len(processed)
+    print(f'Removed {count} unused import{"s" if count != 1 else ""}.')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/android/checkstyle/unused-imports.xml b/tools/android/checkstyle/unused-imports.xml
new file mode 100644
index 0000000..2e29822
--- /dev/null
+++ b/tools/android/checkstyle/unused-imports.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!--
+  See installation instructions: https://sites.google.com/a/chromium.org/dev/developers/checkstyle
+-->
+<module name="Checker">
+  <property name="severity" value="warning"/>
+  <property name="charset" value="UTF-8"/>
+  <module name="SuppressionFilter">
+    <property name="file" value="tools/android/checkstyle/suppressions.xml"/>
+  </module>
+  <module name="SuppressWarningsFilter"/>
+  <module name="TreeWalker">
+    <module name="SuppressWarningsHolder"/>
+    <module name="RedundantImport">
+      <message key="import.redundant" value="Redundant import: {0}."/>
+      <property name="severity" value="error"/>
+    </module>
+    <module name="UnusedImports">
+      <message key="import.unused" value="Unused import: {0}."/>
+      <property name="severity" value="error"/>
+      <property name="processJavadoc" value="true"/>
+    </module>
+  </module>
+</module>
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index 88817e9..39f7f8c 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -711,6 +711,9 @@
         cur_elf_path = elf_path
         elf_path = None
       elif tentative_output_dir:
+        # TODO(crbug.com/1337134): Remove handling the legacy library prefix
+        # 'crazy.' when there is no longer interest in size comparisons for
+        # these pre-N APKs.
         cur_elf_path = os.path.join(
             tentative_output_dir, 'lib.unstripped',
             posixpath.basename(apk_so_path.replace('crazy.', '')))
diff --git a/tools/flakiness/is_flaky.py b/tools/flakiness/is_flaky.py
index c6d9be6d..455284b0 100755
--- a/tools/flakiness/is_flaky.py
+++ b/tools/flakiness/is_flaky.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2014 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -6,8 +6,6 @@
 """Runs a test repeatedly to measure its flakiness. The return code is non-zero
 if the failure rate is higher than the specified threshold, but is not 100%."""
 
-from __future__ import print_function
-
 import argparse
 import multiprocessing.dummy
 import subprocess
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 85e6fb7..d711da4 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -33328,6 +33328,9 @@
 </action>
 
 <action name="TabGroups_CannotCollapse">
+  <obsolete>
+    This action no longer occurs as of 11/2022. Tab groups can always collapse.
+  </obsolete>
   <owner>connily@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index e07957c..4fd2587 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -30839,1059 +30839,6 @@
   <int value="36" label="windows-874"/>
 </enum>
 
-<enum name="EnCrossCLD3LanguageCode">
-  <summary>
-    Hash values for strings of the form &quot;x,y&quot;, where x is either a
-    common English language BCP47 code or &quot;other&quot;, and y is a language
-    code supported by CLD3. Used to report conflicts between HTML language tags
-    and CLD3 language detection.
-  </summary>
-  <int value="-2124369431" label="en-IN,sk"/>
-  <int value="-2116468187" label="en-GB,lv"/>
-  <int value="-2113557848" label="en-NZ,zh-Latn"/>
-  <int value="-2111057442" label="en-AU,eu"/>
-  <int value="-2109862064" label="en-GB,co"/>
-  <int value="-2107569712" label="en-US,mn"/>
-  <int value="-2104732247" label="en-GB,kn"/>
-  <int value="-2095143481" label="en-IN,bg-Latn"/>
-  <int value="-2093238145" label="en-NZ,ru"/>
-  <int value="-2092755960" label="en-GB,pt"/>
-  <int value="-2086002903" label="en-GB,iw"/>
-  <int value="-2083244205" label="en-ZA,is"/>
-  <int value="-2079128291" label="en-CA,pt"/>
-  <int value="-2074513011" label="en-AU,hr"/>
-  <int value="-2070318208" label="en-ZA,zh-Latn"/>
-  <int value="-2067222357" label="en-GB,eu"/>
-  <int value="-2064855342" label="en-CA,uz"/>
-  <int value="-2058651483" label="en-GB,tg"/>
-  <int value="-2056749569" label="other,su"/>
-  <int value="-2050363884" label="en,ps"/>
-  <int value="-2048564427" label="en-US,ceb"/>
-  <int value="-2048426575" label="en,ne"/>
-  <int value="-2044913616" label="en-AU,zu"/>
-  <int value="-2043655475" label="en-IN,sr"/>
-  <int value="-2040518330" label="en-US,is"/>
-  <int value="-2038890712" label="en,is"/>
-  <int value="-2032827489" label="en-US,bn"/>
-  <int value="-2031322000" label="en-US,eo"/>
-  <int value="-2029035680" label="en-ZA,ny"/>
-  <int value="-2028938496" label="en-GB,no"/>
-  <int value="-2024091344" label="en-ZA,no"/>
-  <int value="-2023903582" label="en,de"/>
-  <int value="-2022075322" label="en-ZA,iw"/>
-  <int value="-2016934602" label="other,fi"/>
-  <int value="-2013534235" label="en-IN,cs"/>
-  <int value="-2012682082" label="en,so"/>
-  <int value="-2009823796" label="other,en"/>
-  <int value="-2006294893" label="en-ZA,mi"/>
-  <int value="-2003513780" label="en-CA,ru-Latn"/>
-  <int value="-2000117527" label="en-AU,sl"/>
-  <int value="-1997617048" label="other,yi"/>
-  <int value="-1993954446" label="en-AU,ms"/>
-  <int value="-1985817663" label="en,km"/>
-  <int value="-1982939971" label="en,ku"/>
-  <int value="-1981060640" label="en-NZ,pa"/>
-  <int value="-1969945476" label="en,kk"/>
-  <int value="-1968768037" label="en,be"/>
-  <int value="-1959746105" label="en-NZ,jw"/>
-  <int value="-1944914110" label="en-CA,tr"/>
-  <int value="-1944124391" label="en-NZ,lt"/>
-  <int value="-1940864183" label="en-AU,yue-HK"/>
-  <int value="-1938634095" label="en-AU,ur"/>
-  <int value="-1937334700" label="en-CA,fil"/>
-  <int value="-1936297420" label="en-ZA,th"/>
-  <int value="-1919906366" label="en-US,zh-TW"/>
-  <int value="-1912635719" label="en-IN,hr"/>
-  <int value="-1911121699" label="en-NZ,iw"/>
-  <int value="-1907190634" label="en-GB,sk"/>
-  <int value="-1907045054" label="other,ca"/>
-  <int value="-1902746237" label="en,mr"/>
-  <int value="-1897496014" label="en-NZ,ja"/>
-  <int value="-1896281532" label="en-GB,mr"/>
-  <int value="-1894796887" label="other,uz"/>
-  <int value="-1893186684" label="en-CA,sq"/>
-  <int value="-1888655601" label="en-AU,hmn"/>
-  <int value="-1879544540" label="other,jw"/>
-  <int value="-1879363959" label="en-CA,el-Latn"/>
-  <int value="-1873453878" label="en-US,ht"/>
-  <int value="-1869637891" label="en-CA,te"/>
-  <int value="-1868526533" label="en,zu"/>
-  <int value="-1864675515" label="en-NZ,mr"/>
-  <int value="-1864404923" label="en-NZ,haw"/>
-  <int value="-1863564796" label="en-AU,mg"/>
-  <int value="-1862175609" label="en-US,az"/>
-  <int value="-1860719141" label="en-GB,ja-Latn"/>
-  <int value="-1858480480" label="en,su"/>
-  <int value="-1848050043" label="en-AU,zh"/>
-  <int value="-1844339140" label="en-NZ,bg"/>
-  <int value="-1838958165" label="en,zh-CN"/>
-  <int value="-1837172785" label="en,fy"/>
-  <int value="-1830369415" label="en-AU,sn"/>
-  <int value="-1820239738" label="en-ZA,so"/>
-  <int value="-1814241674" label="en-IN,gu"/>
-  <int value="-1787888508" label="en-NZ,gd"/>
-  <int value="-1786621097" label="other,sd"/>
-  <int value="-1785254801" label="en-AU,fr"/>
-  <int value="-1772875851" label="en-IN,zu"/>
-  <int value="-1771902729" label="en,ar"/>
-  <int value="-1769596689" label="en-AU,si"/>
-  <int value="-1759968348" label="en,und"/>
-  <int value="-1751988881" label="en-AU,ta"/>
-  <int value="-1747832209" label="en-NZ,uz"/>
-  <int value="-1729190557" label="en-ZA,ig"/>
-  <int value="-1728146239" label="en,ta"/>
-  <int value="-1717781349" label="en-GB,st"/>
-  <int value="-1713672416" label="en-CA,sv"/>
-  <int value="-1712698203" label="en-ZA,sd"/>
-  <int value="-1708467253" label="en-CA,unknown"/>
-  <int value="-1705664959" label="en-US,yo"/>
-  <int value="-1705158339" label="en-NZ,ka"/>
-  <int value="-1704290230" label="en-AU,be"/>
-  <int value="-1698540007" label="en-GB,ny"/>
-  <int value="-1698336319" label="en-NZ,unknown"/>
-  <int value="-1694265672" label="en-ZA,sn"/>
-  <int value="-1694050683" label="en,tg"/>
-  <int value="-1691613931" label="other,ja-Latn"/>
-  <int value="-1684149366" label="en-CA,mt"/>
-  <int value="-1665646354" label="en-ZA,fil"/>
-  <int value="-1664646506" label="en-IN,ar"/>
-  <int value="-1652807707" label="en-GB,mt"/>
-  <int value="-1647274992" label="en-IN,ta"/>
-  <int value="-1647174837" label="en-US,ps"/>
-  <int value="-1634052364" label="en-NZ,ml"/>
-  <int value="-1633713836" label="en-IN,sq"/>
-  <int value="-1633251487" label="en-US,jv"/>
-  <int value="-1630949789" label="en-NZ,ca"/>
-  <int value="-1630270728" label="en-NZ,de"/>
-  <int value="-1628320800" label="en-CA,ko"/>
-  <int value="-1623073820" label="en,ru"/>
-  <int value="-1623056651" label="en-ZA,sq"/>
-  <int value="-1616849585" label="en-AU,co"/>
-  <int value="-1615127115" label="en-AU,cy"/>
-  <int value="-1611671963" label="en-IN,lb"/>
-  <int value="-1611623912" label="other,fil"/>
-  <int value="-1607077769" label="en-GB,xh"/>
-  <int value="-1604279981" label="en-IN,hi-Latn"/>
-  <int value="-1596875594" label="other,ky"/>
-  <int value="-1592890693" label="en-GB,ceb"/>
-  <int value="-1592738004" label="en-CA,sr"/>
-  <int value="-1589728436" label="other,lo"/>
-  <int value="-1570014714" label="other,iw"/>
-  <int value="-1564093181" label="en-GB,el"/>
-  <int value="-1556572633" label="en-CA,am"/>
-  <int value="-1554730193" label="en-US,mi"/>
-  <int value="-1552949884" label="en-US,mg"/>
-  <int value="-1549687917" label="en-US,iw"/>
-  <int value="-1544924120" label="en,tr"/>
-  <int value="-1522200631" label="en-NZ,ht"/>
-  <int value="-1520721572" label="en-US,my"/>
-  <int value="-1520389273" label="other,da"/>
-  <int value="-1516606179" label="en-ZA,ko"/>
-  <int value="-1514674113" label="en,th"/>
-  <int value="-1514217919" label="en-AU,uz"/>
-  <int value="-1514197491" label="en-AU,ka"/>
-  <int value="-1513794730" label="en-US,ca"/>
-  <int value="-1511712239" label="en-GB,sl"/>
-  <int value="-1510059118" label="en-NZ,zh-TW"/>
-  <int value="-1507434828" label="en-IN,hmn"/>
-  <int value="-1498956183" label="en-CA,sk"/>
-  <int value="-1496658087" label="en-NZ,cy"/>
-  <int value="-1486809235" label="en-IN,mt"/>
-  <int value="-1479227188" label="en-AU,ky"/>
-  <int value="-1476856301" label="en-US,lb"/>
-  <int value="-1469669231" label="en-GB,sq"/>
-  <int value="-1468074483" label="en-CA,af"/>
-  <int value="-1462099981" label="en-IN,jv"/>
-  <int value="-1461074412" label="en-ZA,zh-TW"/>
-  <int value="-1457647003" label="en-NZ,eu"/>
-  <int value="-1450386960" label="en-CA,nl"/>
-  <int value="-1446631159" label="en-NZ,el-Latn"/>
-  <int value="-1422491922" label="en-US,ka"/>
-  <int value="-1420298629" label="en-ZA,fy"/>
-  <int value="-1416941033" label="en-CA,zh-TW"/>
-  <int value="-1416903380" label="en-ZA,be"/>
-  <int value="-1403910050" label="en-ZA,pl"/>
-  <int value="-1402845617" label="en-GB,fr"/>
-  <int value="-1402681073" label="other,tl"/>
-  <int value="-1399351496" label="en-ZA,gl"/>
-  <int value="-1398520733" label="en-US,ro"/>
-  <int value="-1390125648" label="en-CA,no"/>
-  <int value="-1388486986" label="en-CA,eo"/>
-  <int value="-1385835372" label="other,ta"/>
-  <int value="-1383130458" label="en-US,gd"/>
-  <int value="-1382832620" label="en-AU,mr"/>
-  <int value="-1382630626" label="en-US,hi"/>
-  <int value="-1376708570" label="en-GB,lb"/>
-  <int value="-1372289390" label="en-GB,nl"/>
-  <int value="-1370590322" label="en,pt"/>
-  <int value="-1369722574" label="en-GB,ig"/>
-  <int value="-1367992379" label="en-ZA,it"/>
-  <int value="-1366543906" label="en-AU,unknown"/>
-  <int value="-1360539588" label="en-ZA,mk"/>
-  <int value="-1357419592" label="en-CA,ig"/>
-  <int value="-1353345099" label="en-CA,cs"/>
-  <int value="-1346503932" label="en,fa"/>
-  <int value="-1346156856" label="en-IN,pl"/>
-  <int value="-1343690599" label="en-CA,zh-Latn"/>
-  <int value="-1331214321" label="en-ZA,unknown"/>
-  <int value="-1329522963" label="other,sv"/>
-  <int value="-1324503751" label="other,hmn"/>
-  <int value="-1310042673" label="other,it"/>
-  <int value="-1309690314" label="other,nl"/>
-  <int value="-1309674747" label="en-IN,tl"/>
-  <int value="-1301792573" label="en-US,pa"/>
-  <int value="-1298978218" label="en-ZA,ru"/>
-  <int value="-1298210853" label="en-AU,ru-Latn"/>
-  <int value="-1295927056" label="en-ZA,nl"/>
-  <int value="-1292209370" label="en-AU,hi"/>
-  <int value="-1290497188" label="en-GB,ru-Latn"/>
-  <int value="-1290070339" label="en-AU,ja"/>
-  <int value="-1283031458" label="en-AU,ht"/>
-  <int value="-1281458280" label="en,el-Latn"/>
-  <int value="-1278516305" label="en-US,ml"/>
-  <int value="-1263108473" label="en-IN,ru-Latn"/>
-  <int value="-1259042225" label="other,pl"/>
-  <int value="-1238995224" label="en-US,hy"/>
-  <int value="-1238591345" label="en-NZ,kk"/>
-  <int value="-1233706328" label="en,en"/>
-  <int value="-1228999462" label="en-AU,es"/>
-  <int value="-1227601505" label="en-US,ky"/>
-  <int value="-1224781996" label="en-IN,te"/>
-  <int value="-1224753420" label="en-US,fy"/>
-  <int value="-1219920190" label="en-ZA,hmn"/>
-  <int value="-1217746309" label="en-GB,hmn"/>
-  <int value="-1213938554" label="en-AU,ne"/>
-  <int value="-1213583239" label="en,da"/>
-  <int value="-1209455268" label="en-IN,la"/>
-  <int value="-1208444202" label="en-US,co"/>
-  <int value="-1207597587" label="other,bs"/>
-  <int value="-1196089827" label="en-GB,te"/>
-  <int value="-1194882730" label="en-CA,bs"/>
-  <int value="-1183487896" label="en,tl"/>
-  <int value="-1182285832" label="en-AU,ar"/>
-  <int value="-1180706012" label="en-US,ku"/>
-  <int value="-1176858165" label="en-NZ,es"/>
-  <int value="-1161664630" label="en-CA,so"/>
-  <int value="-1150612958" label="en-GB,ml"/>
-  <int value="-1149861387" label="other,el-Latn"/>
-  <int value="-1147733157" label="en-US,zh-CN"/>
-  <int value="-1146067341" label="en-US,fil"/>
-  <int value="-1134207512" label="en-NZ,lb"/>
-  <int value="-1133970848" label="en-CA,ht"/>
-  <int value="-1131269514" label="en-NZ,km"/>
-  <int value="-1122870775" label="en-IN,ga"/>
-  <int value="-1119552856" label="en-GB,hy"/>
-  <int value="-1118006347" label="en-NZ,su"/>
-  <int value="-1111896399" label="en-ZA,cs"/>
-  <int value="-1111659918" label="en-ZA,bn"/>
-  <int value="-1110229326" label="en-IN,zh-CN"/>
-  <int value="-1109349887" label="en-US,bs"/>
-  <int value="-1104794613" label="en-ZA,eo"/>
-  <int value="-1102200262" label="en-AU,bg"/>
-  <int value="-1087479434" label="en-NZ,gu"/>
-  <int value="-1086494101" label="en-IN,en"/>
-  <int value="-1085453048" label="en-NZ,tl"/>
-  <int value="-1083832142" label="en-ZA,fr"/>
-  <int value="-1082841040" label="en-AU,no"/>
-  <int value="-1078817533" label="en-IN,ja-Latn"/>
-  <int value="-1061831796" label="other,sw"/>
-  <int value="-1060276304" label="en-AU,ml"/>
-  <int value="-1059536520" label="en-GB,zh-CN"/>
-  <int value="-1058009879" label="en-AU,ku"/>
-  <int value="-1049361969" label="en-CA,yo"/>
-  <int value="-1048166271" label="en-IN,ceb"/>
-  <int value="-1042239713" label="en-ZA,ne"/>
-  <int value="-1041196877" label="en-NZ,lo"/>
-  <int value="-1039980655" label="en-GB,et"/>
-  <int value="-1039749771" label="en-GB,so"/>
-  <int value="-1038109255" label="en,mk"/>
-  <int value="-1035837896" label="en-AU,su"/>
-  <int value="-1033591490" label="en-AU,sv"/>
-  <int value="-1030469686" label="en-IN,haw"/>
-  <int value="-1028065279" label="en-GB,und"/>
-  <int value="-1026066097" label="en-IN,vi"/>
-  <int value="-1026028202" label="other,fr"/>
-  <int value="-1014607888" label="en-GB,ps"/>
-  <int value="-1009703136" label="en-US,gu"/>
-  <int value="-999407605" label="en-AU,sr"/>
-  <int value="-998551972" label="other,st"/>
-  <int value="-997491813" label="other,no"/>
-  <int value="-997355335" label="en-IN,hy"/>
-  <int value="-996302242" label="en-US,sn"/>
-  <int value="-994546623" label="en,gd"/>
-  <int value="-981430978" label="en-IN,zh-Latn"/>
-  <int value="-980040557" label="en,ky"/>
-  <int value="-975362715" label="en-ZA,tl"/>
-  <int value="-973176337" label="en-ZA,am"/>
-  <int value="-969434649" label="en-CA,ro"/>
-  <int value="-965565591" label="en-ZA,bg"/>
-  <int value="-963786426" label="en-GB,ha"/>
-  <int value="-961625891" label="en-NZ,et"/>
-  <int value="-955553888" label="en-ZA,mg"/>
-  <int value="-952843725" label="en-US,mk"/>
-  <int value="-949401757" label="en,my"/>
-  <int value="-942062362" label="en-US,zh-Latn"/>
-  <int value="-931047164" label="en-IN,cy"/>
-  <int value="-922858301" label="en-GB,gu"/>
-  <int value="-921098649" label="en-CA,ja-Latn"/>
-  <int value="-919289357" label="en-AU,vi"/>
-  <int value="-918912162" label="en-CA,co"/>
-  <int value="-916808527" label="other,ko"/>
-  <int value="-911043903" label="en,fil"/>
-  <int value="-906245796" label="en-IN,su"/>
-  <int value="-899190372" label="en-GB,unknown"/>
-  <int value="-897318896" label="en-IN,af"/>
-  <int value="-894681263" label="en-CA,fy"/>
-  <int value="-888512967" label="other,kk"/>
-  <int value="-888161970" label="en-ZA,az"/>
-  <int value="-884692633" label="en-GB,ru"/>
-  <int value="-867330946" label="en-GB,sm"/>
-  <int value="-858362606" label="en-IN,nl"/>
-  <int value="-857227100" label="en-IN,jw"/>
-  <int value="-856399552" label="en-ZA,yi"/>
-  <int value="-855471302" label="en-US,ta"/>
-  <int value="-843023273" label="en-ZA,eu"/>
-  <int value="-836893384" label="en-AU,xh"/>
-  <int value="-836276118" label="en-ZA,my"/>
-  <int value="-832538906" label="en-ZA,el-Latn"/>
-  <int value="-829280752" label="en-US,es"/>
-  <int value="-825403216" label="other,ar"/>
-  <int value="-822848490" label="en-IN,mn"/>
-  <int value="-821693819" label="en-GB,ms"/>
-  <int value="-815159881" label="other,pa"/>
-  <int value="-809183331" label="en-ZA,ga"/>
-  <int value="-807570056" label="en-CA,yi"/>
-  <int value="-804692123" label="en-NZ,fr"/>
-  <int value="-802011698" label="en-CA,ka"/>
-  <int value="-800653639" label="en-NZ,ny"/>
-  <int value="-799944497" label="en-IN,ml"/>
-  <int value="-786069036" label="en,hy"/>
-  <int value="-781392865" label="en-AU,fy"/>
-  <int value="-774741229" label="en-US,uk"/>
-  <int value="-774705893" label="en,ru-Latn"/>
-  <int value="-771415808" label="en-NZ,sm"/>
-  <int value="-770599199" label="en-NZ,la"/>
-  <int value="-769370804" label="en-ZA,ht"/>
-  <int value="-766020458" label="en,sl"/>
-  <int value="-761784084" label="other,si"/>
-  <int value="-755296599" label="en-AU,ca"/>
-  <int value="-749134072" label="en-CA,be"/>
-  <int value="-747589726" label="en-CA,pl"/>
-  <int value="-746521712" label="en-AU,te"/>
-  <int value="-730553903" label="en-IN,st"/>
-  <int value="-718567737" label="en,uk"/>
-  <int value="-712484664" label="en-NZ,mn"/>
-  <int value="-711855661" label="en-US,el-Latn"/>
-  <int value="-703823200" label="en-US,sm"/>
-  <int value="-697784898" label="en-US,sd"/>
-  <int value="-693708098" label="en-IN,hu"/>
-  <int value="-689084995" label="en-AU,nl"/>
-  <int value="-687121797" label="en-IN,ms"/>
-  <int value="-683936001" label="en-GB,fil"/>
-  <int value="-681691326" label="en-IN,eu"/>
-  <int value="-677909491" label="other,de"/>
-  <int value="-664749191" label="en,zh-Latn"/>
-  <int value="-664666756" label="en-NZ,yi"/>
-  <int value="-659037096" label="en-CA,az"/>
-  <int value="-653328792" label="en,la"/>
-  <int value="-651792270" label="en-CA,ga"/>
-  <int value="-647724785" label="en-IN,hi"/>
-  <int value="-640995328" label="en-NZ,bn"/>
-  <int value="-629813533" label="en-IN,kn"/>
-  <int value="-618249296" label="en-IN,bg"/>
-  <int value="-615263868" label="en-GB,gl"/>
-  <int value="-614537549" label="en-AU,mn"/>
-  <int value="-608103664" label="en-CA,es"/>
-  <int value="-599897624" label="en-IN,tr"/>
-  <int value="-580470151" label="en-IN,sm"/>
-  <int value="-579152612" label="en-ZA,id"/>
-  <int value="-578031600" label="en,sk"/>
-  <int value="-576525627" label="en-AU,ps"/>
-  <int value="-569450071" label="other,ur"/>
-  <int value="-567245265" label="en-AU,jw"/>
-  <int value="-564888613" label="en-IN,eo"/>
-  <int value="-562158532" label="other,zh-Latn"/>
-  <int value="-560384338" label="en-CA,sd"/>
-  <int value="-557565099" label="en-NZ,ha"/>
-  <int value="-556698502" label="en-GB,pa"/>
-  <int value="-555419731" label="en-US,gl"/>
-  <int value="-552151539" label="en-AU,fi"/>
-  <int value="-548315734" label="en-IN,ka"/>
-  <int value="-544980397" label="en-AU,mt"/>
-  <int value="-542018328" label="other,es"/>
-  <int value="-534482286" label="en-ZA,ro"/>
-  <int value="-533872798" label="en-AU,zh-Latn"/>
-  <int value="-533834685" label="en-IN,de"/>
-  <int value="-522871017" label="en-ZA,lv"/>
-  <int value="-519390252" label="en-GB,hi-Latn"/>
-  <int value="-512294090" label="en,hr"/>
-  <int value="-506627221" label="en-IN,si"/>
-  <int value="-505475005" label="en-ZA,et"/>
-  <int value="-496363418" label="en-NZ,mk"/>
-  <int value="-495925829" label="en-GB,cy"/>
-  <int value="-494116460" label="en-AU,yo"/>
-  <int value="-492538502" label="en-ZA,lo"/>
-  <int value="-489487792" label="en-NZ,hi-Latn"/>
-  <int value="-488070282" label="en-NZ,sd"/>
-  <int value="-484244598" label="other,sk"/>
-  <int value="-479580786" label="en-GB,mn"/>
-  <int value="-477712301" label="en-CA,ru"/>
-  <int value="-473350786" label="en-AU,lo"/>
-  <int value="-469999914" label="en-GB,la"/>
-  <int value="-469484616" label="en-IN,co"/>
-  <int value="-464923601" label="en-US,mt"/>
-  <int value="-463472731" label="other,sq"/>
-  <int value="-462215397" label="en-CA,lb"/>
-  <int value="-460414518" label="en-US,la"/>
-  <int value="-449171923" label="en-IN,mk"/>
-  <int value="-438919066" label="en-AU,ru"/>
-  <int value="-437634847" label="other,ku"/>
-  <int value="-432262667" label="other,zh-CN"/>
-  <int value="-429170059" label="en-ZA,jv"/>
-  <int value="-428711284" label="other,hr"/>
-  <int value="-426218528" label="en-US,lt"/>
-  <int value="-419753035" label="en-US,lo"/>
-  <int value="-418116563" label="en-AU,so"/>
-  <int value="-416557773" label="en-IN,km"/>
-  <int value="-409223124" label="en-NZ,cs"/>
-  <int value="-408820412" label="en-IN,no"/>
-  <int value="-406936471" label="en,mi"/>
-  <int value="-404916241" label="en-GB,ne"/>
-  <int value="-403948453" label="en-IN,lv"/>
-  <int value="-398623564" label="en-GB,id"/>
-  <int value="-396833557" label="en-AU,ig"/>
-  <int value="-396028589" label="en,hmn"/>
-  <int value="-378569290" label="en-US,zh"/>
-  <int value="-368423696" label="en,uz"/>
-  <int value="-366405340" label="en,ko"/>
-  <int value="-362116022" label="en-US,ar"/>
-  <int value="-358433124" label="en-ZA,en"/>
-  <int value="-356540717" label="en-ZA,ml"/>
-  <int value="-355403459" label="en-NZ,ne"/>
-  <int value="-354189899" label="en-US,lv"/>
-  <int value="-350618888" label="en,bs"/>
-  <int value="-348068803" label="en-US,el"/>
-  <int value="-347968268" label="en-IN,pa"/>
-  <int value="-344950263" label="en-US,sv"/>
-  <int value="-340173781" label="en,sw"/>
-  <int value="-337628003" label="en-ZA,xh"/>
-  <int value="-328800060" label="en-ZA,ceb"/>
-  <int value="-328614553" label="en-ZA,da"/>
-  <int value="-327839206" label="en-CA,is"/>
-  <int value="-318840877" label="en-NZ,yo"/>
-  <int value="-309531049" label="en,gu"/>
-  <int value="-308798721" label="en-IN,sl"/>
-  <int value="-307369173" label="en-US,hi-Latn"/>
-  <int value="-300476925" label="en,ml"/>
-  <int value="-298058163" label="en-GB,tl"/>
-  <int value="-291300455" label="en-CA,jw"/>
-  <int value="-291188106" label="en-GB,th"/>
-  <int value="-289299006" label="en-US,ny"/>
-  <int value="-286225855" label="en-ZA,sr"/>
-  <int value="-284562486" label="en-ZA,ky"/>
-  <int value="-279786682" label="en-US,und"/>
-  <int value="-273619891" label="en-CA,ne"/>
-  <int value="-266075643" label="en-CA,tg"/>
-  <int value="-244658645" label="en-CA,cy"/>
-  <int value="-243735299" label="en-AU,lt"/>
-  <int value="-238154724" label="en-US,ms"/>
-  <int value="-238083370" label="other,ka"/>
-  <int value="-236445557" label="en-US,ne"/>
-  <int value="-234681308" label="en,mt"/>
-  <int value="-227668781" label="en-IN,kk"/>
-  <int value="-226564202" label="en-AU,iw"/>
-  <int value="-220301883" label="en-GB,yue-HK"/>
-  <int value="-212757062" label="en-ZA,mt"/>
-  <int value="-212529805" label="en-CA,de"/>
-  <int value="-210208396" label="en-IN,ky"/>
-  <int value="-207049992" label="en-US,tl"/>
-  <int value="-195613326" label="en-US,xh"/>
-  <int value="-194304961" label="en-AU,ha"/>
-  <int value="-183211755" label="en-NZ,ga"/>
-  <int value="-180588871" label="other,uk"/>
-  <int value="-176562730" label="en-ZA,la"/>
-  <int value="-175945266" label="en-ZA,ta"/>
-  <int value="-175546622" label="en,ga"/>
-  <int value="-172830708" label="en-GB,fa"/>
-  <int value="-170360146" label="en-CA,fi"/>
-  <int value="-169624558" label="en-CA,zh-CN"/>
-  <int value="-169367928" label="en-ZA,sw"/>
-  <int value="-158046757" label="en-CA,hu"/>
-  <int value="-157371194" label="en-ZA,hi-Latn"/>
-  <int value="-156478388" label="en,zh-TW"/>
-  <int value="-151899928" label="en-NZ,hi"/>
-  <int value="-147938422" label="en-IN,el"/>
-  <int value="-145185628" label="en-CA,ps"/>
-  <int value="-143554786" label="en-GB,si"/>
-  <int value="-129286720" label="en-IN,yo"/>
-  <int value="-127996003" label="en-GB,yi"/>
-  <int value="-126871272" label="en-CA,my"/>
-  <int value="-123482448" label="other,te"/>
-  <int value="-119609134" label="en-AU,my"/>
-  <int value="-116594264" label="en-IN,fr"/>
-  <int value="-111605959" label="en-IN,my"/>
-  <int value="-92573461" label="en-US,haw"/>
-  <int value="-82976780" label="en-NZ,und"/>
-  <int value="-78204086" label="en-IN,es"/>
-  <int value="-76540753" label="en-GB,ht"/>
-  <int value="-75045139" label="en-AU,haw"/>
-  <int value="-73112949" label="en-GB,be"/>
-  <int value="-72394213" label="other,vi"/>
-  <int value="-69623762" label="en-NZ,zh"/>
-  <int value="-69356326" label="other,id"/>
-  <int value="-56300824" label="en-CA,sw"/>
-  <int value="-53596266" label="other,bg"/>
-  <int value="-52394574" label="other,ru"/>
-  <int value="-50281907" label="en-GB,mi"/>
-  <int value="-39535324" label="en,yo"/>
-  <int value="-28950181" label="en,jv"/>
-  <int value="-26764693" label="other,ru-Latn"/>
-  <int value="-24388218" label="en-US,unknown"/>
-  <int value="-15862101" label="en-IN,et"/>
-  <int value="-15388410" label="en,lt"/>
-  <int value="-8240870" label="en-ZA,pa"/>
-  <int value="-7019923" label="en-ZA,sm"/>
-  <int value="-2212741" label="en-AU,az"/>
-  <int value="393297" label="other,eo"/>
-  <int value="571301" label="en-US,fi"/>
-  <int value="2586472" label="en,hi"/>
-  <int value="11142866" label="en-IN,gd"/>
-  <int value="12797257" label="en-US,yue-HK"/>
-  <int value="12962928" label="en-US,hr"/>
-  <int value="32976640" label="en-IN,und"/>
-  <int value="34221237" label="other,haw"/>
-  <int value="34572536" label="en-NZ,bg-Latn"/>
-  <int value="35868033" label="other,mg"/>
-  <int value="37620184" label="en-AU,mk"/>
-  <int value="37790914" label="en-NZ,ko"/>
-  <int value="40545721" label="en-IN,ht"/>
-  <int value="41189157" label="other,hi"/>
-  <int value="42657077" label="en-IN,mr"/>
-  <int value="43554136" label="en-CA,zu"/>
-  <int value="46974212" label="en-US,et"/>
-  <int value="55397648" label="en-ZA,hr"/>
-  <int value="59721356" label="en,st"/>
-  <int value="61120844" label="other,gu"/>
-  <int value="61901143" label="en-CA,lo"/>
-  <int value="69561606" label="en-NZ,mt"/>
-  <int value="80248107" label="en-NZ,ky"/>
-  <int value="80343050" label="other,unknown"/>
-  <int value="96729755" label="en-IN,ig"/>
-  <int value="106556254" label="en-IN,fi"/>
-  <int value="106824120" label="other,ig"/>
-  <int value="109858538" label="other,kn"/>
-  <int value="110814535" label="en-US,sl"/>
-  <int value="111512557" label="en-CA,ca"/>
-  <int value="111639146" label="en-US,ko"/>
-  <int value="118312454" label="en,pl"/>
-  <int value="122516567" label="en-ZA,sk"/>
-  <int value="124014428" label="en-CA,uk"/>
-  <int value="125937660" label="en-US,de"/>
-  <int value="130279541" label="en-AU,hu"/>
-  <int value="131823616" label="en-CA,ur"/>
-  <int value="134776967" label="en-CA,sl"/>
-  <int value="137726805" label="en-NZ,el"/>
-  <int value="137743856" label="other,my"/>
-  <int value="138088365" label="en-AU,bn"/>
-  <int value="143906557" label="en,sq"/>
-  <int value="148633933" label="en-US,su"/>
-  <int value="149249801" label="en-ZA,vi"/>
-  <int value="149254673" label="en-NZ,hu"/>
-  <int value="159338274" label="en-CA,haw"/>
-  <int value="160108056" label="en-CA,th"/>
-  <int value="173175536" label="en-ZA,ur"/>
-  <int value="174638312" label="other,sr"/>
-  <int value="176692935" label="en-AU,en"/>
-  <int value="177507595" label="en-ZA,es"/>
-  <int value="179820951" label="en-CA,zh"/>
-  <int value="183621141" label="other,yo"/>
-  <int value="189106370" label="en-US,eu"/>
-  <int value="194694507" label="en-NZ,sq"/>
-  <int value="203847267" label="en-ZA,zh-CN"/>
-  <int value="204011687" label="en-CA,ml"/>
-  <int value="206430050" label="en-GB,es"/>
-  <int value="210100759" label="en-CA,xh"/>
-  <int value="211459852" label="en,vi"/>
-  <int value="212244145" label="other,af"/>
-  <int value="217457619" label="en-CA,ha"/>
-  <int value="226603980" label="en-IN,it"/>
-  <int value="228447752" label="en-CA,gl"/>
-  <int value="229522242" label="en-AU,id"/>
-  <int value="231593443" label="en-CA,mg"/>
-  <int value="233491613" label="en-NZ,sl"/>
-  <int value="238615518" label="en-NZ,ru-Latn"/>
-  <int value="240447639" label="en-NZ,ig"/>
-  <int value="241686897" label="other,co"/>
-  <int value="241878472" label="en-AU,tl"/>
-  <int value="248618927" label="en-AU,el-Latn"/>
-  <int value="255346854" label="en-GB,gd"/>
-  <int value="262272920" label="en,sm"/>
-  <int value="262946543" label="en-US,am"/>
-  <int value="264871477" label="en-CA,kn"/>
-  <int value="266556636" label="en-ZA,zh"/>
-  <int value="273592672" label="en,sv"/>
-  <int value="279930804" label="other,und"/>
-  <int value="281605263" label="en,ja"/>
-  <int value="297068506" label="en-AU,hi-Latn"/>
-  <int value="307890939" label="en-ZA,ka"/>
-  <int value="311580662" label="en-AU,pl"/>
-  <int value="314700048" label="en-GB,fy"/>
-  <int value="321957105" label="en-AU,fil"/>
-  <int value="330092459" label="en,no"/>
-  <int value="333750610" label="en-NZ,ur"/>
-  <int value="338185331" label="en,bg-Latn"/>
-  <int value="340118597" label="en-ZA,ms"/>
-  <int value="346399527" label="other,pt"/>
-  <int value="346807260" label="en-GB,az"/>
-  <int value="351405982" label="other,lb"/>
-  <int value="352829367" label="other,ro"/>
-  <int value="354495805" label="en-AU,ja-Latn"/>
-  <int value="360333241" label="en,pa"/>
-  <int value="360482886" label="other,km"/>
-  <int value="361147661" label="en-GB,ja"/>
-  <int value="361177790" label="en-IN,yue-HK"/>
-  <int value="369729502" label="en-IN,ur"/>
-  <int value="374070776" label="en-GB,yo"/>
-  <int value="382794171" label="other,az"/>
-  <int value="385029378" label="en-ZA,hu"/>
-  <int value="386122260" label="en,ig"/>
-  <int value="390230115" label="en,xh"/>
-  <int value="390230404" label="en-ZA,bg-Latn"/>
-  <int value="395804990" label="en-NZ,sk"/>
-  <int value="403914044" label="en-ZA,uz"/>
-  <int value="409408505" label="en-AU,lb"/>
-  <int value="413238463" label="other,mn"/>
-  <int value="415649361" label="en-US,th"/>
-  <int value="416845327" label="en-ZA,co"/>
-  <int value="421338918" label="other,mi"/>
-  <int value="425550335" label="en-US,cy"/>
-  <int value="426525808" label="en-IN,da"/>
-  <int value="427905069" label="en,bg"/>
-  <int value="428418059" label="en-US,hu"/>
-  <int value="433730304" label="other,sm"/>
-  <int value="435389133" label="en-ZA,hi"/>
-  <int value="435774878" label="en-ZA,lt"/>
-  <int value="438943486" label="en,sn"/>
-  <int value="441009234" label="en-AU,und"/>
-  <int value="446363395" label="en-NZ,is"/>
-  <int value="446396562" label="en-CA,en"/>
-  <int value="448777481" label="en-US,da"/>
-  <int value="453143797" label="en-IN,ru"/>
-  <int value="455023577" label="en-AU,kk"/>
-  <int value="464193252" label="en-GB,bn"/>
-  <int value="469426247" label="en-NZ,da"/>
-  <int value="470968744" label="en-IN,am"/>
-  <int value="471525594" label="en-GB,bg-Latn"/>
-  <int value="471740150" label="en-CA,tl"/>
-  <int value="477790180" label="other,bn"/>
-  <int value="481497515" label="other,ga"/>
-  <int value="482150171" label="en-GB,uz"/>
-  <int value="484422880" label="en-IN,sw"/>
-  <int value="486304785" label="en-NZ,ar"/>
-  <int value="486576942" label="en-CA,et"/>
-  <int value="492739479" label="en-GB,jw"/>
-  <int value="504950639" label="en-IN,pt"/>
-  <int value="507474490" label="other,mr"/>
-  <int value="511298624" label="en-AU,bg-Latn"/>
-  <int value="519370622" label="other,hi-Latn"/>
-  <int value="519539246" label="en-NZ,te"/>
-  <int value="523832586" label="en-ZA,ha"/>
-  <int value="527153503" label="en-AU,uk"/>
-  <int value="529364835" label="other,hu"/>
-  <int value="535527955" label="en-IN,ko"/>
-  <int value="539528919" label="en-GB,is"/>
-  <int value="549589790" label="en-IN,az"/>
-  <int value="550300686" label="en,yi"/>
-  <int value="559874907" label="en-ZA,lb"/>
-  <int value="571750049" label="en-CA,pa"/>
-  <int value="578680520" label="en-GB,vi"/>
-  <int value="584050776" label="other,ne"/>
-  <int value="586304261" label="en,fr"/>
-  <int value="586492233" label="en-ZA,haw"/>
-  <int value="595670153" label="other,be"/>
-  <int value="595917413" label="en-CA,id"/>
-  <int value="599526823" label="en-IN,ku"/>
-  <int value="605876339" label="other,lt"/>
-  <int value="610831978" label="other,yue-HK"/>
-  <int value="612847367" label="en-ZA,te"/>
-  <int value="614830922" label="other,ml"/>
-  <int value="616504159" label="en-GB,jv"/>
-  <int value="621990796" label="other,sl"/>
-  <int value="624672740" label="en-GB,zh"/>
-  <int value="626970505" label="en,ht"/>
-  <int value="628097668" label="en-IN,sd"/>
-  <int value="639569313" label="en-NZ,yue-HK"/>
-  <int value="640262038" label="en-AU,sm"/>
-  <int value="641686626" label="en-US,ru"/>
-  <int value="646613899" label="en-IN,sn"/>
-  <int value="647296114" label="en-US,ur"/>
-  <int value="648256160" label="other,gl"/>
-  <int value="648502016" label="en-CA,fr"/>
-  <int value="651467435" label="en-AU,pt"/>
-  <int value="653336951" label="en,bn"/>
-  <int value="659151888" label="en,unknown"/>
-  <int value="659781560" label="en-GB,eo"/>
-  <int value="661495710" label="en,am"/>
-  <int value="668031905" label="en,nl"/>
-  <int value="670118633" label="en-GB,ro"/>
-  <int value="672889168" label="en-NZ,sw"/>
-  <int value="676999142" label="other,ms"/>
-  <int value="678632750" label="other,ja"/>
-  <int value="680060380" label="en-US,yi"/>
-  <int value="680453726" label="en,hi-Latn"/>
-  <int value="682029315" label="other,tg"/>
-  <int value="683983274" label="en-IN,ha"/>
-  <int value="687124847" label="en,cs"/>
-  <int value="705544038" label="en-IN,ca"/>
-  <int value="712186903" label="en-IN,lo"/>
-  <int value="724168729" label="en-IN,fy"/>
-  <int value="737198162" label="en-GB,sd"/>
-  <int value="739427185" label="en-GB,bs"/>
-  <int value="744516660" label="en,gl"/>
-  <int value="756534358" label="en-IN,bn"/>
-  <int value="758976688" label="en-IN,gl"/>
-  <int value="759357339" label="en,sd"/>
-  <int value="762656539" label="en-US,ig"/>
-  <int value="786031713" label="en,yue-HK"/>
-  <int value="794132649" label="en-IN,sv"/>
-  <int value="796385096" label="en-GB,bg"/>
-  <int value="796611332" label="en-ZA,kn"/>
-  <int value="798691984" label="en-US,ha"/>
-  <int value="799101140" label="en-IN,ny"/>
-  <int value="801133153" label="en-GB,mg"/>
-  <int value="802275724" label="en-IN,zh-TW"/>
-  <int value="804316451" label="other,el"/>
-  <int value="807787788" label="en-ZA,gd"/>
-  <int value="809250169" label="en-US,cs"/>
-  <int value="816096178" label="en-GB,my"/>
-  <int value="824645258" label="en-US,sk"/>
-  <int value="826118132" label="en-US,jw"/>
-  <int value="826558712" label="en-ZA,sv"/>
-  <int value="849084143" label="en,it"/>
-  <int value="850862273" label="en-AU,de"/>
-  <int value="853352499" label="other,so"/>
-  <int value="854823242" label="en-ZA,ku"/>
-  <int value="855074740" label="en-CA,el"/>
-  <int value="857152633" label="en-CA,hi"/>
-  <int value="857603803" label="other,et"/>
-  <int value="859133433" label="en-NZ,sn"/>
-  <int value="865348028" label="en,ha"/>
-  <int value="880686769" label="en-GB,ku"/>
-  <int value="880915916" label="other,ht"/>
-  <int value="882319904" label="en-CA,sn"/>
-  <int value="889210765" label="en-CA,gd"/>
-  <int value="899191103" label="en-CA,mr"/>
-  <int value="904203484" label="en-NZ,co"/>
-  <int value="906138796" label="en-US,bg-Latn"/>
-  <int value="909977985" label="en-GB,ga"/>
-  <int value="911105608" label="en-CA,lv"/>
-  <int value="912157886" label="en-NZ,ceb"/>
-  <int value="912705685" label="en-ZA,el"/>
-  <int value="918457519" label="en-NZ,sr"/>
-  <int value="923188761" label="en-US,bg"/>
-  <int value="923423627" label="en,mn"/>
-  <int value="926439457" label="en-IN,unknown"/>
-  <int value="928679325" label="en-CA,ny"/>
-  <int value="931138724" label="en,eu"/>
-  <int value="934631232" label="other,ny"/>
-  <int value="937631019" label="en-US,ru-Latn"/>
-  <int value="938838496" label="en-CA,hmn"/>
-  <int value="948185011" label="en-CA,lt"/>
-  <int value="955180290" label="en-CA,si"/>
-  <int value="956064637" label="en-ZA,af"/>
-  <int value="960562184" label="en-NZ,si"/>
-  <int value="965503536" label="en-CA,hr"/>
-  <int value="966547063" label="en-CA,iw"/>
-  <int value="967746332" label="en-NZ,ja-Latn"/>
-  <int value="973763517" label="en-US,sq"/>
-  <int value="974585410" label="en-IN,is"/>
-  <int value="977145120" label="other,la"/>
-  <int value="977677962" label="en-NZ,lv"/>
-  <int value="982872922" label="en-IN,mi"/>
-  <int value="987399566" label="en-ZA,mr"/>
-  <int value="990147394" label="other,gd"/>
-  <int value="991829124" label="en-AU,gu"/>
-  <int value="998803921" label="en-GB,fi"/>
-  <int value="1002420538" label="en-CA,fa"/>
-  <int value="1008823931" label="en-NZ,am"/>
-  <int value="1013384242" label="en-ZA,hy"/>
-  <int value="1015585848" label="en-CA,ku"/>
-  <int value="1017943799" label="en-ZA,tr"/>
-  <int value="1020968666" label="en-US,so"/>
-  <int value="1021819779" label="en-US,si"/>
-  <int value="1022348319" label="other,fy"/>
-  <int value="1022666993" label="en-IN,be"/>
-  <int value="1023969309" label="en-AU,pa"/>
-  <int value="1029598412" label="en-GB,hu"/>
-  <int value="1038405709" label="en-ZA,pt"/>
-  <int value="1041158278" label="other,zh"/>
-  <int value="1041314309" label="en-GB,sv"/>
-  <int value="1041843225" label="en-AU,mi"/>
-  <int value="1044512953" label="en-IN,bs"/>
-  <int value="1047774851" label="en-NZ,th"/>
-  <int value="1047990359" label="en-CA,st"/>
-  <int value="1055706381" label="other,mt"/>
-  <int value="1058027180" label="en-NZ,ps"/>
-  <int value="1062243141" label="en-AU,el"/>
-  <int value="1063843295" label="en-IN,el-Latn"/>
-  <int value="1070881406" label="en-IN,iw"/>
-  <int value="1072572125" label="en,az"/>
-  <int value="1076247598" label="en-NZ,uk"/>
-  <int value="1077340584" label="en-NZ,mi"/>
-  <int value="1078066471" label="en-NZ,my"/>
-  <int value="1086284012" label="other,th"/>
-  <int value="1088333377" label="en-NZ,fi"/>
-  <int value="1099612922" label="en-ZA,und"/>
-  <int value="1100066240" label="en-AU,gl"/>
-  <int value="1101277515" label="en-AU,bs"/>
-  <int value="1102196185" label="en-GB,zh-Latn"/>
-  <int value="1102359128" label="en,co"/>
-  <int value="1104996635" label="en-GB,ka"/>
-  <int value="1109268156" label="en-AU,sd"/>
-  <int value="1113936347" label="en-US,ga"/>
-  <int value="1116909928" label="en-ZA,km"/>
-  <int value="1128555043" label="en-NZ,be"/>
-  <int value="1135410106" label="en-CA,it"/>
-  <int value="1135936276" label="en,af"/>
-  <int value="1139383998" label="en,haw"/>
-  <int value="1155102742" label="en-AU,sq"/>
-  <int value="1163093350" label="en-ZA,ar"/>
-  <int value="1167163022" label="en-GB,kk"/>
-  <int value="1168246222" label="en-US,tg"/>
-  <int value="1169881078" label="en,id"/>
-  <int value="1170715716" label="en-ZA,zu"/>
-  <int value="1171944607" label="en-NZ,zh-CN"/>
-  <int value="1174248653" label="en-GB,zu"/>
-  <int value="1175423418" label="other,ha"/>
-  <int value="1175589237" label="en-IN,zh"/>
-  <int value="1175618948" label="en-US,no"/>
-  <int value="1178260016" label="en-AU,lv"/>
-  <int value="1178359238" label="en,hu"/>
-  <int value="1181212519" label="en,mg"/>
-  <int value="1182312689" label="other,lv"/>
-  <int value="1185020245" label="en-CA,mn"/>
-  <int value="1192415688" label="en-AU,ga"/>
-  <int value="1197096620" label="en-IN,fa"/>
-  <int value="1198326653" label="en-US,af"/>
-  <int value="1201895414" label="en,sr"/>
-  <int value="1204411090" label="en-GB,sr"/>
-  <int value="1206951812" label="en-NZ,en"/>
-  <int value="1207559379" label="other,ceb"/>
-  <int value="1207746876" label="en-GB,ar"/>
-  <int value="1210191695" label="en-GB,hr"/>
-  <int value="1210299740" label="en-US,fa"/>
-  <int value="1218130469" label="en-IN,yi"/>
-  <int value="1233341588" label="en-AU,da"/>
-  <int value="1239978088" label="en,el"/>
-  <int value="1256797102" label="en-ZA,fa"/>
-  <int value="1260927179" label="en-GB,ur"/>
-  <int value="1262922540" label="en-ZA,uk"/>
-  <int value="1264329857" label="en-NZ,tg"/>
-  <int value="1278539454" label="en-US,hmn"/>
-  <int value="1280510255" label="en-NZ,hr"/>
-  <int value="1280736521" label="en-ZA,sl"/>
-  <int value="1286376309" label="en-IN,xh"/>
-  <int value="1292870564" label="en-ZA,ru-Latn"/>
-  <int value="1300968709" label="en-GB,it"/>
-  <int value="1302667839" label="en-NZ,bs"/>
-  <int value="1303482305" label="other,zh-TW"/>
-  <int value="1306008814" label="en-NZ,pt"/>
-  <int value="1307519081" label="other,fa"/>
-  <int value="1310524684" label="en-AU,tg"/>
-  <int value="1311997351" label="en-NZ,ku"/>
-  <int value="1317436581" label="en,ka"/>
-  <int value="1326944743" label="en-AU,tr"/>
-  <int value="1329589180" label="en-NZ,zu"/>
-  <int value="1333183401" label="en,te"/>
-  <int value="1335991765" label="en-NZ,af"/>
-  <int value="1340188273" label="en,kn"/>
-  <int value="1344361345" label="en-ZA,ps"/>
-  <int value="1345672063" label="en-GB,lt"/>
-  <int value="1354542174" label="other,hy"/>
-  <int value="1354544720" label="en-CA,sm"/>
-  <int value="1366667779" label="en-AU,la"/>
-  <int value="1368223495" label="other,is"/>
-  <int value="1375141921" label="en-NZ,mg"/>
-  <int value="1375516436" label="other,jv"/>
-  <int value="1377425950" label="en-NZ,az"/>
-  <int value="1378327312" label="en-AU,zh-TW"/>
-  <int value="1382586179" label="en-GB,ko"/>
-  <int value="1383657387" label="en-GB,zh-TW"/>
-  <int value="1384498167" label="en-CA,ja"/>
-  <int value="1389280901" label="en-AU,eo"/>
-  <int value="1393996692" label="en-CA,mi"/>
-  <int value="1395222628" label="en-IN,lt"/>
-  <int value="1398402282" label="en-GB,de"/>
-  <int value="1402000053" label="en-GB,ky"/>
-  <int value="1404684826" label="en-CA,yue-HK"/>
-  <int value="1416181656" label="en,ny"/>
-  <int value="1418241073" label="en-NZ,sv"/>
-  <int value="1420980063" label="en-AU,ro"/>
-  <int value="1422442520" label="en-AU,jv"/>
-  <int value="1430525845" label="en-AU,sk"/>
-  <int value="1440048775" label="en-GB,ca"/>
-  <int value="1440610021" label="other,cs"/>
-  <int value="1448954659" label="en-AU,yi"/>
-  <int value="1454462350" label="en-US,tr"/>
-  <int value="1455512265" label="en-CA,da"/>
-  <int value="1455668867" label="en-US,sr"/>
-  <int value="1464251629" label="en-GB,uk"/>
-  <int value="1468669496" label="en-GB,su"/>
-  <int value="1468930251" label="en-ZA,tg"/>
-  <int value="1473595362" label="en,et"/>
-  <int value="1475867184" label="other,ps"/>
-  <int value="1479752599" label="en-NZ,so"/>
-  <int value="1483792223" label="en,jw"/>
-  <int value="1486918374" label="en-CA,gu"/>
-  <int value="1492342066" label="en-IN,ro"/>
-  <int value="1494396409" label="en-NZ,tr"/>
-  <int value="1502339637" label="en,ms"/>
-  <int value="1512489951" label="en-US,kk"/>
-  <int value="1516505763" label="en-IN,uk"/>
-  <int value="1525021570" label="en-GB,hi"/>
-  <int value="1529621431" label="en-IN,mg"/>
-  <int value="1534291662" label="en,fi"/>
-  <int value="1541318518" label="en-CA,ar"/>
-  <int value="1545921996" label="en,cy"/>
-  <int value="1547798712" label="en-CA,hy"/>
-  <int value="1554560505" label="en,iw"/>
-  <int value="1556599784" label="en-US,zu"/>
-  <int value="1560108635" label="en-CA,bg"/>
-  <int value="1569869322" label="en,lv"/>
-  <int value="1571010464" label="other,tr"/>
-  <int value="1574218451" label="en,ja-Latn"/>
-  <int value="1574455066" label="en-NZ,hy"/>
-  <int value="1577813196" label="en-ZA,ja-Latn"/>
-  <int value="1583748372" label="en-US,uz"/>
-  <int value="1584277030" label="en,lo"/>
-  <int value="1586371836" label="en-GB,haw"/>
-  <int value="1587065378" label="en-CA,ceb"/>
-  <int value="1587149206" label="en-AU,is"/>
-  <int value="1587448881" label="other,bg-Latn"/>
-  <int value="1595122469" label="en-GB,am"/>
-  <int value="1599809239" label="en-NZ,eo"/>
-  <int value="1602933018" label="en-AU,km"/>
-  <int value="1606599170" label="en-GB,af"/>
-  <int value="1616893188" label="en-GB,en"/>
-  <int value="1617301307" label="en-US,vi"/>
-  <int value="1620733201" label="en-ZA,st"/>
-  <int value="1622221024" label="en-NZ,st"/>
-  <int value="1625230863" label="en-ZA,ca"/>
-  <int value="1627858810" label="en-CA,su"/>
-  <int value="1631878770" label="en-CA,eu"/>
-  <int value="1633252733" label="en-CA,und"/>
-  <int value="1640305574" label="en-CA,ms"/>
-  <int value="1649537917" label="en-NZ,id"/>
-  <int value="1650086272" label="en-IN,ja"/>
-  <int value="1654964809" label="en-GB,ta"/>
-  <int value="1658068744" label="en-ZA,si"/>
-  <int value="1668672261" label="en-AU,zh-CN"/>
-  <int value="1674861874" label="en-AU,af"/>
-  <int value="1674862709" label="en-AU,ko"/>
-  <int value="1678320412" label="en-US,sw"/>
-  <int value="1682694795" label="en-ZA,jw"/>
-  <int value="1682821330" label="en,ro"/>
-  <int value="1685893517" label="en-IN,so"/>
-  <int value="1688465225" label="en-NZ,gl"/>
-  <int value="1693278011" label="en-US,pt"/>
-  <int value="1697603371" label="en,si"/>
-  <int value="1700824821" label="en-GB,tr"/>
-  <int value="1717190578" label="en-CA,bn"/>
-  <int value="1721644578" label="en-NZ,nl"/>
-  <int value="1723571120" label="en-NZ,ta"/>
-  <int value="1725099187" label="en,zh"/>
-  <int value="1737627322" label="en-ZA,cy"/>
-  <int value="1740225427" label="en-GB,cs"/>
-  <int value="1742804144" label="en-US,te"/>
-  <int value="1744275224" label="en-ZA,fi"/>
-  <int value="1749696454" label="other,cy"/>
-  <int value="1753505573" label="en-ZA,mn"/>
-  <int value="1772273660" label="other,am"/>
-  <int value="1787055860" label="en-CA,ta"/>
-  <int value="1795956429" label="en-AU,ny"/>
-  <int value="1797503688" label="en-NZ,jv"/>
-  <int value="1805209460" label="en-IN,th"/>
-  <int value="1825180324" label="en-GB,pl"/>
-  <int value="1826276933" label="en-US,km"/>
-  <int value="1837257554" label="en-IN,id"/>
-  <int value="1839203236" label="en-CA,la"/>
-  <int value="1840601524" label="en-US,pl"/>
-  <int value="1843812704" label="en-US,en"/>
-  <int value="1845750026" label="en-GB,mk"/>
-  <int value="1850895272" label="en-ZA,su"/>
-  <int value="1858092254" label="en-NZ,fy"/>
-  <int value="1859062446" label="en-NZ,ms"/>
-  <int value="1864323264" label="en-NZ,hmn"/>
-  <int value="1879419731" label="en-NZ,fil"/>
-  <int value="1887245165" label="en-IN,ne"/>
-  <int value="1887547959" label="en-AU,hy"/>
-  <int value="1896229543" label="en-AU,st"/>
-  <int value="1897866500" label="en-AU,cs"/>
-  <int value="1914113466" label="en-GB,sn"/>
-  <int value="1916036344" label="en-AU,th"/>
-  <int value="1921346058" label="en-NZ,kn"/>
-  <int value="1921468722" label="en-GB,lo"/>
-  <int value="1922305307" label="en,ca"/>
-  <int value="1923055656" label="other,sn"/>
-  <int value="1929310230" label="en-IN,tg"/>
-  <int value="1935021242" label="en-GB,el-Latn"/>
-  <int value="1947337323" label="en-GB,sw"/>
-  <int value="1950716531" label="en,lb"/>
-  <int value="1953379543" label="en-ZA,yo"/>
-  <int value="1954146782" label="en-IN,ps"/>
-  <int value="1955147896" label="en-US,ja"/>
-  <int value="1960593815" label="en-IN,uz"/>
-  <int value="1971945016" label="en-AU,am"/>
-  <int value="1972836537" label="en-GB,km"/>
-  <int value="1975943948" label="en-AU,gd"/>
-  <int value="1981144369" label="en-US,be"/>
-  <int value="1990402435" label="en-ZA,ja"/>
-  <int value="1991206873" label="en,es"/>
-  <int value="1992336755" label="en-NZ,xh"/>
-  <int value="1993640855" label="en-CA,jv"/>
-  <int value="1998909729" label="en-ZA,kk"/>
-  <int value="2008193378" label="en-NZ,it"/>
-  <int value="2009383888" label="other,xh"/>
-  <int value="2019528786" label="en-CA,bg-Latn"/>
-  <int value="2019768967" label="other,eu"/>
-  <int value="2028809726" label="en-CA,km"/>
-  <int value="2031218406" label="en,ur"/>
-  <int value="2036627878" label="en-CA,mk"/>
-  <int value="2041001332" label="en-NZ,no"/>
-  <int value="2044661620" label="en-AU,sw"/>
-  <int value="2045704410" label="en-AU,it"/>
-  <int value="2047493862" label="en-CA,ky"/>
-  <int value="2048503615" label="en,eo"/>
-  <int value="2050034631" label="en-US,mr"/>
-  <int value="2052081632" label="en-AU,ceb"/>
-  <int value="2058678293" label="en-US,kn"/>
-  <int value="2063559514" label="en-US,st"/>
-  <int value="2069198284" label="en-IN,fil"/>
-  <int value="2070565410" label="en-ZA,de"/>
-  <int value="2075422927" label="en-AU,fa"/>
-  <int value="2077918936" label="en-AU,kn"/>
-  <int value="2078538264" label="en-AU,et"/>
-  <int value="2078639052" label="en-US,nl"/>
-  <int value="2083592559" label="en-US,it"/>
-  <int value="2087547308" label="en-GB,da"/>
-  <int value="2088017334" label="en-CA,hi-Latn"/>
-  <int value="2088167089" label="en-NZ,vi"/>
-  <int value="2095083633" label="en-ZA,gu"/>
-  <int value="2095959023" label="en-NZ,pl"/>
-  <int value="2099045123" label="en-NZ,ro"/>
-  <int value="2099107983" label="en-ZA,yue-HK"/>
-  <int value="2100025793" label="en-US,id"/>
-  <int value="2115803061" label="en-CA,kk"/>
-  <int value="2116112642" label="en-US,fr"/>
-  <int value="2116383804" label="en,ceb"/>
-  <int value="2121668277" label="en-CA,vi"/>
-  <int value="2123533843" label="other,zu"/>
-  <int value="2132483133" label="en-US,ja-Latn"/>
-  <int value="2137580597" label="en-NZ,fa"/>
-  <int value="2141671912" label="other,mk"/>
-  <int value="2144565498" label="en-ZA,bs"/>
-</enum>
-
 <enum name="EndRecordingReason">
   <int value="0" label="Stop recording button"/>
   <int value="1" label="Display or window closing"/>
@@ -42669,6 +41616,7 @@
   <int value="4393" label="DocumentLoaderDeliveryTypeNavigationalPrefetch"/>
   <int value="4394" label="SpeculationRulesHeader"/>
   <int value="4395" label="SpeculationRulesDocumentRules"/>
+  <int value="4396" label="FederatedCredentialManagementIframe"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index 19a1091e..f8ff3ac 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -2172,7 +2172,7 @@
 </histogram>
 
 <histogram name="PumpkinInstaller.InstallationSuccess" enum="BooleanSuccess"
-    expires_after="2023-01-01">
+    expires_after="2023-09-01">
   <owner>akihiroota@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index 690019f..188d259 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -637,7 +637,7 @@
   <token key="ArcUserTypes" variants="ArcUserTypes"/>
 </histogram>
 
-<histogram name="Arc.Auth.NumAccounts" units="count" expires_after="2023-01-01">
+<histogram name="Arc.Auth.NumAccounts" units="count" expires_after="2023-07-01">
   <owner>anastasiian@google.com</owner>
   <owner>mhasank@google.com</owner>
   <owner>arc-core@google.com</owner>
@@ -647,7 +647,7 @@
   </summary>
 </histogram>
 
-<histogram name="Arc.Auth.PercentAccounts" units="%" expires_after="2023-01-01">
+<histogram name="Arc.Auth.PercentAccounts" units="%" expires_after="2023-07-01">
   <owner>anastasiian@google.com</owner>
   <owner>mhasank@google.com</owner>
   <owner>arc-core@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/assistant/histograms.xml b/tools/metrics/histograms/metadata/assistant/histograms.xml
index 6b89ed6..124ec47 100644
--- a/tools/metrics/histograms/metadata/assistant/histograms.xml
+++ b/tools/metrics/histograms/metadata/assistant/histograms.xml
@@ -95,7 +95,7 @@
 </histogram>
 
 <histogram name="Assistant.HotwordEnableNotification" enum="BooleanHit"
-    expires_after="2022-12-31">
+    expires_after="2023-10-31">
   <owner>updowndota@chromium.org</owner>
   <owner>croissant-eng@chromium.org</owner>
   <summary>
@@ -165,7 +165,7 @@
 </histogram>
 
 <histogram name="Assistant.QueryCountPerEntryPoint" enum="AssistantEntryPoint"
-    expires_after="2022-12-26">
+    expires_after="2023-10-31">
   <owner>xiaohuic@chromium.org</owner>
   <owner>croissant-eng@chromium.org</owner>
   <summary>Number of queries fired for each entry point.</summary>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml
index fc4fa36..a951f14c 100644
--- a/tools/metrics/histograms/metadata/gpu/histograms.xml
+++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -518,12 +518,14 @@
 </histogram>
 
 <histogram name="GPU.DirectComposition.CompositionMode2.VideoOrCanvas"
-    enum="DxgiFramePresentationMode" expires_after="2021-12-31">
+    enum="DxgiFramePresentationMode" expires_after="2023-05-22">
   <owner>sunnyps@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     How the Desktop Window Manager presented Chrome's DirectComposition layers
-    of video or canvas elements to the screen. Only recorded on Windows.
+    of video or canvas elements to the screen. Only recorded on Windows. NOTE:
+    This metric was expired and not collecting data between 2021-12-31 and
+    crrev.com/c/4041850 (M110).
   </summary>
 </histogram>
 
@@ -591,26 +593,6 @@
   </summary>
 </histogram>
 
-<histogram name="GPU.DirectComposition.DecodeSwapChainCreationResult"
-    enum="Hresult" expires_after="M76">
-  <owner>sunnyps@chromium.org</owner>
-  <owner>zmo@chromium.org</owner>
-  <summary>
-    Result of calling CreateDecodeSwapChainForCompositionSurfaceHandle. Recorded
-    when decode swap chain is created.
-  </summary>
-</histogram>
-
-<histogram name="GPU.DirectComposition.DecodeSwapChainNotUsedReason"
-    enum="DecodeSwapChainNotUsedReason" expires_after="M76">
-  <owner>sunnyps@chromium.org</owner>
-  <owner>zmo@chromium.org</owner>
-  <summary>
-    The reason decode swap chain wasn't used to present a video frame. Recorded
-    on each present. See also GPU.DirectComposition.VideoPresentationMode.
-  </summary>
-</histogram>
-
 <histogram name="GPU.DirectComposition.HardwareOverlaysSupported"
     enum="BooleanOverlaySupported" expires_after="2023-04-16">
   <owner>magchen@chromium.org</owner>
@@ -666,18 +648,6 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="GPU.DirectComposition.SwapChainCreationResult2"
-    enum="Hresult" expires_after="2019-05-31">
-<!-- Name completed by histogram_suffixes name="GPU.DirectComposition.OverlayFormat" -->
-
-  <owner>sunnyps@chromium.org</owner>
-  <owner>zmo@chromium.org</owner>
-  <summary>
-    Whether creating swap chain for overlay format succeeded. Recorded once per
-    swap chain creation.
-  </summary>
-</histogram>
-
 <histogram base="true" name="GPU.DirectComposition.SwapChainCreationResult3"
     enum="Hresult" expires_after="2023-04-16">
 <!-- Name completed by histogram_suffixes name="GPU.ProtectedVideoType" -->
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
index 1256000b6..c5a793f 100644
--- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -2166,13 +2166,6 @@
   <affected-histogram name="GoogleUpdate.Result.TimeWindow.Unknown"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="GPU_DirectComposition_OverlayFormat" separator=".">
-  <suffix name="BGRA" label="BGRA"/>
-  <suffix name="NV12" label="NV12"/>
-  <suffix name="YUY2" label="YUY2"/>
-  <affected-histogram name="GPU.DirectComposition.SwapChainCreationResult2"/>
-</histogram_suffixes>
-
 <histogram_suffixes name="GPU_ProtectedVideoType" separator=".">
   <suffix name="Clear" label="Clear"/>
   <suffix name="HardwareProtected" label="HardwareProtected"/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index af4e9d4..d60a4785 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -2553,6 +2553,16 @@
   <token key="VideoCodec" variants="VideoCodec"/>
 </histogram>
 
+<histogram name="Media.EME.Widevine.SoftwareSecure.SystemCode"
+    enum="CdmSystemCode" expires_after="2023-05-07">
+  <owner>xhwang@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    System code in promise rejection when using Widevine key system in software
+    secure mode.
+  </summary>
+</histogram>
+
 <histogram name="Media.EME.Widevine.VideoCapability.HasEmptyRobustness"
     enum="BooleanEmpty" expires_after="2023-03-19">
   <owner>xhwang@chromium.org</owner>
@@ -2623,14 +2633,6 @@
   <token key="KeySystem" variants="KeySystem"/>
 </histogram>
 
-<histogram name="Media.EME.{KeySystem}.SystemCode" enum="CdmSystemCode"
-    expires_after="2023-05-07">
-  <owner>xhwang@chromium.org</owner>
-  <owner>media-dev@chromium.org</owner>
-  <summary>System code in promise rejection.</summary>
-  <token key="KeySystem" variants="KeySystemWithRobustness"/>
-</histogram>
-
 <histogram name="Media.EME.{KeySystem}.TimeTo{ResolveOrReject}.{EmeApi}"
     units="ms" expires_after="2023-05-07">
   <owner>xhwang@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 2c1f94f..4a800933 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -9501,7 +9501,7 @@
 </histogram>
 
 <histogram name="OAuth2Login.SessionRestoreTimeToSuccess" units="ms"
-    expires_after="2022-12-04">
+    expires_after="2023-06-04">
   <owner>anastasiian@chromium.org</owner>
   <owner>sinhak@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 90980380..3ee3a31e 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -2699,7 +2699,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordStoreInitResult2"
-    enum="BooleanSuccess" expires_after="M110">
+    enum="BooleanSuccess" expires_after="M115">
   <owner>vasilii@chromium.org</owner>
   <owner>src/components/password_manager/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml
index 14aa519..0a7be9b 100644
--- a/tools/metrics/histograms/metadata/platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -1748,8 +1748,13 @@
   <owner>mutexlox@chromium.org</owner>
   <owner>cros-telemetry@google.com</owner>
   <summary>
-    Count of crashes (unclean shutdown) during the previous day, or the most
-    recent day the device was in use. Reported at most once a day.
+    Count of unclean OS shutdowns during the previous day, or the most recent
+    day the device was in use. Specifically, the counter is incremented during
+    boot if the OS did not shut down cleanly and the previous shutdown was not
+    due to a kernel crash (kernel crashes are counted elsewere) and the previous
+    shutdown did not occur while the device was suspended (failures while
+    suspended are assumed to be the battery running down). Reported at most once
+    a day.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/quick_answers/histograms.xml b/tools/metrics/histograms/metadata/quick_answers/histograms.xml
index ab9378e..d6770cd 100644
--- a/tools/metrics/histograms/metadata/quick_answers/histograms.xml
+++ b/tools/metrics/histograms/metadata/quick_answers/histograms.xml
@@ -102,7 +102,7 @@
 </histogram>
 
 <histogram name="QuickAnswers.ContextMenu.Close.Duration{InteractionType}"
-    units="ms" expires_after="2022-12-31">
+    units="ms" expires_after="2023-10-31">
   <owner>updowndota@chromium.org</owner>
   <owner>croissant-eng@chromium.org</owner>
   <summary>
@@ -240,7 +240,7 @@
 </histogram>
 
 <histogram name="QuickAnswers.Result.Duration{QuickAnswersClickResultType}"
-    units="ms" expires_after="2022-12-31">
+    units="ms" expires_after="2023-10-31">
   <owner>updowndota@chromium.org</owner>
   <owner>llin@google.com</owner>
   <owner>croissant-eng@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index 08c17fea..559dd70 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -2069,34 +2069,6 @@
   </token>
 </histogram>
 
-<histogram name="WebRTC.SystemMaxConsecutiveBytesDelayed{IPProtocolType}"
-    units="units" expires_after="M81">
-  <owner>qingsi@google.com</owner>
-  <owner>jeroendb@google.com</owner>
-  <summary>
-    The maximum of consecutive delayed bytes caused by EWOULDBLOCKs from system.
-    This happens when system can't send any packet synchronously at that moment.
-    {IPProtocolType}
-  </summary>
-  <token key="IPProtocolType" variants="IPProtocolType">
-    <variant name=""/>
-  </token>
-</histogram>
-
-<histogram name="WebRTC.SystemPercentPacketsDelayed{IPProtocolType}" units="%"
-    expires_after="M81">
-  <owner>qingsi@google.com</owner>
-  <owner>jeroendb@google.com</owner>
-  <summary>
-    The percentage of packets delayed due to ERR_IO_PENDING from system in a
-    WebRTC socket. This happens when system can't send any packet synchronously
-    at that moment. {IPProtocolType}
-  </summary>
-  <token key="IPProtocolType" variants="IPProtocolType">
-    <variant name=""/>
-  </token>
-</histogram>
-
 <histogram name="WebRTC.SystemSendPacketDuration{IPProtocolType}" units="ms"
     expires_after="M81">
   <owner>qingsi@google.com</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 727b90c..5301822d 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": "2556b96927dbfb0a7f8877d998558f5ba685cb52",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/c5fb93e71014315880f4e38620f11cad5cca0a2c/trace_processor_shell.exe"
+            "hash": "eec291620013625a856fa2b4d0c3e359e8bacbef",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/51908f273fa158b58c6336afa93b65838c6ff3cf/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "6373f26144aad58f230d11d6a91efda5a09c9873",
             "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "beba9acd7bedfb03c3544e09c1c6bd24be77b2ce",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/c5fb93e71014315880f4e38620f11cad5cca0a2c/trace_processor_shell"
+            "hash": "ad435e8dc0ca52d5f8a53d4c22e3152c9f92cea3",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/a7d3afea3356f2bce05beb6d9eca9be4402a0e8a/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "5f47ee79e59d00bf3889d30ca52315522c158040",
             "full_remote_path": "perfetto-luci-artifacts/v31.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "b1447193ea6aea5af1f5c25587715003882a2be4",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/4a6b28e79fbe57c881d8e6185ebe0fbf38d76ee3/trace_processor_shell"
+            "hash": "780b06e0c37caf80f458aa8b84af2eb27fd3f720",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/a7d3afea3356f2bce05beb6d9eca9be4402a0e8a/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/rust/update_rust.py b/tools/rust/update_rust.py
index 5d96d70..2243e299 100755
--- a/tools/rust/update_rust.py
+++ b/tools/rust/update_rust.py
@@ -27,7 +27,7 @@
     os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'clang',
                  'scripts'))
 
-RUST_REVISION = '20221101'
+RUST_REVISION = '20221118'
 RUST_SUB_REVISION = 1
 
 # Trunk on 2022-10-15.
@@ -45,13 +45,13 @@
 # This should almost always be None. When a breakage happens the fallback should
 # be temporary. Once fixed, the applicable revision(s) above should be updated
 # and FALLBACK_CLANG_VERSION should be reset to None.
-FALLBACK_CLANG_VERSION = 'llvmorg-16-init-9369-g87a20868-1'
+FALLBACK_CLANG_VERSION = None
 
 # Hash of src/stage0.json, which itself contains the stage0 toolchain hashes.
 # We trust the Rust build system checks, but to ensure it is not tampered with
 # itself check the hash.
 STAGE0_JSON_SHA256 = (
-    'c0909797c1901c32985a40ec6b54b9ccad8464aa5dbebd20235db094fee1a6bc')
+    '07f4d4ddde6910a70f16f372309525528ff42499fb50317e6ded4bfe1b6ce7cf')
 
 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
 CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..'))
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index 4e40dc6cb..5c319622 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -182,15 +182,6 @@
   return base::FeatureList::IsEnabled(::features::kEnhancedNetworkVoices);
 }
 
-BASE_FEATURE(kAccessibilityOSSettingsVisibility,
-             "AccessibilityOSSettingsVisibility",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-bool IsAccessibilityOSSettingsVisibilityEnabled() {
-  return base::FeatureList::IsEnabled(
-      ::features::kAccessibilityOSSettingsVisibility);
-}
-
 BASE_FEATURE(kExperimentalAccessibilityColorEnhancementSettings,
              "ExperimentalAccessibilityColorEnhancementSettings",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h
index 05a78c69..7154e38 100644
--- a/ui/accessibility/accessibility_features.h
+++ b/ui/accessibility/accessibility_features.h
@@ -138,12 +138,6 @@
 // Returns true if network-based voices are enabled in Select-to-speak.
 AX_BASE_EXPORT bool IsEnhancedNetworkVoicesEnabled();
 
-// Enables improved Accessibility OS Settings visibility.
-AX_BASE_EXPORT BASE_DECLARE_FEATURE(kAccessibilityOSSettingsVisibility);
-
-// Returns true if improved Accessibility OS Settings visibility is enabled.
-AX_BASE_EXPORT bool IsAccessibilityOSSettingsVisibilityEnabled();
-
 // Enables the experimental color enhancements settings.
 AX_BASE_EXPORT BASE_DECLARE_FEATURE(
     kExperimentalAccessibilityColorEnhancementSettings);
diff --git a/ui/android/java/res/values/attrs.xml b/ui/android/java/res/values/attrs.xml
index 7f1f806..e3651b2e 100644
--- a/ui/android/java/res/values/attrs.xml
+++ b/ui/android/java/res/values/attrs.xml
@@ -33,10 +33,9 @@
     </declare-styleable>
 
     <!-- The attributes prefixed with 'global' are used to control the button, link and URL colors
-         throughout the app. They are defined in ThemeOverlay.DynamicButtons and are applied to the
-         activity theme. This enables us to apply dynamic colors to the mentioned UI elements. These
-         attributes may not be set in the themes, so the code dealing with them should handle their
-         absence. -->
+         throughout the app and are defined in the activity theme. This enables us to apply
+         dynamic colors to the mentioned UI elements. These attributes may not be set in some
+         contexts, e.g. WebView, so the code dealing with them should handle their absence. -->
     <attr name="globalFilledButtonBgColor" format="color"/>
     <attr name="globalFilledButtonTextColor" format="reference"/>
     <attr name="globalTextButtonTextColor" format="reference"/>
diff --git a/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java b/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
index 45d7057..fbcaa1f 100644
--- a/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
@@ -7,6 +7,7 @@
 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;
@@ -15,7 +16,6 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
-import org.chromium.base.TraceEvent;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -32,6 +32,9 @@
     /** 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();
 
@@ -139,25 +142,60 @@
      * @return The size of the bottom margin which most likely is exactly the keyboard size.
      */
     public int calculateKeyboardHeight(View rootView) {
-        try (TraceEvent te =
-                        TraceEvent.scoped("KeyboardVisibilityDelegate.calculateKeyboardHeight")) {
-            Rect appRect = new Rect();
-            rootView.getWindowVisibleDisplayFrame(appRect);
+        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 there is no bottom margin, the keyboard is not showing.
+        if (bottomMargin <= 0) return 0;
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             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);
+    }
+
+    /**
+     * Returns the total keyboard widget height.
+     *
+     * In addition to the keyboard itself, this may include accessory bars and related widgets that
+     * behave as-if they're part of the keyboard if the embedder supports them.
+     */
+    public int calculateTotalKeyboardHeight(View rootView) {
+        return calculateKeyboardHeight(rootView);
     }
 
     /**
@@ -180,7 +218,9 @@
      */
     protected boolean isAndroidSoftKeyboardShowing(Context context, View view) {
         View rootView = view.getRootView();
-        return rootView != null && calculateKeyboardHeight(rootView) > 0;
+        return rootView != null
+                && calculateKeyboardHeight(rootView)
+                > calculateKeyboardDetectionThreshold(context, rootView);
     }
 
     /**
diff --git a/ui/display/manager/display_change_observer.cc b/ui/display/manager/display_change_observer.cc
index 4159631..6faca0d 100644
--- a/ui/display/manager/display_change_observer.cc
+++ b/ui/display/manager/display_change_observer.cc
@@ -257,10 +257,15 @@
         DCHECK_EQ(Display::InternalDisplayId(), state->display_id());
       SetInternalDisplayIds({state->display_id()});
 
-      if (state->current_mode() && state->native_mode() &&
-          !display_manager_->IsDisplayIdValid(state->display_id())) {
-        // Update the internal display info if it's not already registered.
-        // It'll be treated as new display in |UpdateDisplaysWith()|.
+      if (state->native_mode() &&
+          (!display_manager_->IsDisplayIdValid(state->display_id()) ||
+           !state->current_mode())) {
+        // Register the internal display info if
+        // 1) If it's not already registered. It'll be treated as
+        // new display in |UpdateDisplaysWith()|.
+        // 2) If it's not connected, because the display info will not
+        // be updated in |UpdateDisplaysWith()|, which will skips the
+        // disconnected displays.
         ManagedDisplayInfo new_info =
             CreateManagedDisplayInfo(state, state->native_mode());
         display_manager_->UpdateInternalDisplay(new_info);
diff --git a/ui/display/test/display_manager_test_api.h b/ui/display/test/display_manager_test_api.h
index 28cf3f9..5e73004 100644
--- a/ui/display/test/display_manager_test_api.h
+++ b/ui/display/test/display_manager_test_api.h
@@ -46,10 +46,6 @@
   // the format of the display spec.
   void UpdateDisplay(const std::string& display_specs);
 
-  // Sets the display id for internal display and
-  // update the display mode list if necessary.
-  void SetInternalDisplayId(int64_t id);
-
   // Set the 1st display as an internal display and returns the display Id for
   // the internal display.
   int64_t SetFirstDisplayAsInternalDisplay();
@@ -70,6 +66,9 @@
 
  private:
   friend class ScopedSetInternalDisplayId;
+  // Sets the display id for internal display and
+  // update the display mode list if necessary.
+  void SetInternalDisplayId(int64_t id);
 
   // Indicate the maximum number of displays that chrome device can support.
   static size_t maximum_support_display_;
diff --git a/ui/gfx/x/event.cc b/ui/gfx/x/event.cc
index cbe57f594..002a088 100644
--- a/ui/gfx/x/event.cc
+++ b/ui/gfx/x/event.cc
@@ -59,26 +59,23 @@
   ReadEvent(this, connection, &buf);
 }
 
-Event::Event(Event&& event)
-    : send_event_(event.send_event_),
-      sequence_(event.sequence_),
-      type_id_(event.type_id_),
-      event_(std::move(event.event_)),
-      window_(std::move(event.window_)) {
-  memset(&event, 0, sizeof(Event));
+Event::Event(Event&& event) {
+  operator=(std::move(event));
 }
 
 Event& Event::operator=(Event&& event) {
-  send_event_ = event.send_event_;
-  sequence_ = event.sequence_;
-  type_id_ = event.type_id_;
-  //`window_` is owned by `event_`. Set it to nullptr before calling
-  //`event.reset()` to avoid holding a dangling ptr.
-  window_ = nullptr;
-  event_.reset();
-  event_ = std::move(event.event_);
+  // `window_` borrowed from `event_`, so it must be reset first.
   window_ = std::move(event.window_);
-  memset(&event, 0, sizeof(Event));
+  event_ = std::move(event.event_);
+  type_id_ = event.type_id_;
+  sequence_ = event.sequence_;
+  send_event_ = event.send_event_;
+
+  // Clear the old instance, to make sure an invalid state isn't going to be
+  // used:
+  event.type_id_ = 0;
+  event.sequence_ = 0;
+  event.send_event_ = false;
   return *this;
 }
 
diff --git a/ui/gl/dcomp_surface_proxy.h b/ui/gl/dcomp_surface_proxy.h
index f29b397..2f453b6 100644
--- a/ui/gl/dcomp_surface_proxy.h
+++ b/ui/gl/dcomp_surface_proxy.h
@@ -7,6 +7,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/video_types.h"
 
 namespace gl {
 
@@ -16,6 +17,8 @@
   virtual HANDLE GetSurfaceHandle() = 0;
   virtual void SetRect(const gfx::Rect& window_relative_rect) = 0;
   virtual void SetParentWindow(HWND parent) = 0;
+  virtual void SetProtectedVideoType(
+      gfx::ProtectedVideoType protected_video_type) = 0;
 
  protected:
   friend class base::RefCounted<DCOMPSurfaceProxy>;
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc
index cfddfdb..e79138f 100644
--- a/ui/gl/swap_chain_presenter.cc
+++ b/ui/gl/swap_chain_presenter.cc
@@ -864,8 +864,6 @@
   if (ShouldUseVideoProcessorScaling())
     return false;
 
-  auto not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
-
   bool nv12_supported =
       (swap_chain_format == DXGI_FORMAT_NV12) &&
       (DXGI_FORMAT_NV12 == GetDirectCompositionSDROverlayFormat());
@@ -922,28 +920,10 @@
       }
       ReleaseSwapChainResources();
       failed_to_present_decode_swapchain_ = true;
-      not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
       DLOG(ERROR)
           << "Present to decode swap chain failed - falling back to blit";
-    } else if (!is_decoder_texture) {
-      not_used_reason = DecodeSwapChainNotUsedReason::kNonDecoderTexture;
-    } else if (is_shared_texture) {
-      not_used_reason = DecodeSwapChainNotUsedReason::kSharedTexture;
-    } else if (is_unitary_texture_array) {
-      not_used_reason = DecodeSwapChainNotUsedReason::kUnitaryTextureArray;
-    } else if (!compatible_transform) {
-      not_used_reason = DecodeSwapChainNotUsedReason::kIncompatibleTransform;
     }
-  } else if (!texture) {
-    not_used_reason = DecodeSwapChainNotUsedReason::kSoftwareFrame;
-  } else if (!nv12_supported) {
-    not_used_reason = DecodeSwapChainNotUsedReason::kNv12NotSupported;
-  } else if (failed_to_present_decode_swapchain_) {
-    not_used_reason = DecodeSwapChainNotUsedReason::kFailedToPresent;
   }
-
-  UMA_HISTOGRAM_ENUMERATION(
-      "GPU.DirectComposition.DecodeSwapChainNotUsedReason", not_used_reason);
   return false;
 }
 
@@ -996,8 +976,6 @@
         media_factory->CreateDecodeSwapChainForCompositionSurfaceHandle(
             d3d11_device_.Get(), swap_chain_handle_.Get(), &desc,
             decode_resource_.Get(), nullptr, &decode_swap_chain_);
-    base::UmaHistogramSparse(
-        "GPU.DirectComposition.DecodeSwapChainCreationResult", hr);
     if (FAILED(hr)) {
       DLOG(ERROR) << "CreateDecodeSwapChainForCompositionSurfaceHandle failed "
                      "with error 0x"
@@ -1190,7 +1168,7 @@
       GetSwapChainFormat(params.protected_video_type, use_hdr_swap_chain);
   bool swap_chain_format_changed = swap_chain_format != swap_chain_format_;
   bool toggle_protected_video =
-      protected_video_type_ != params.protected_video_type;
+      swap_chain_protected_video_type_ != params.protected_video_type;
 
   if (swap_chain_ && !swap_chain_resized && !swap_chain_format_changed &&
       !toggle_protected_video && last_presented_images_ == params.images) {
@@ -1333,9 +1311,6 @@
   UMA_HISTOGRAM_ENUMERATION("GPU.DirectComposition.VideoPresentationMode",
                             presentation_mode);
 
-  UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.DecodeSwapChainUsed",
-                        !!decode_swap_chain_);
-
   TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("gpu.service"),
                        "SwapChain::Present", TRACE_EVENT_SCOPE_THREAD,
                        "PixelFormat", DxgiFormatToString(swap_chain_format_),
@@ -1394,6 +1369,8 @@
   dcomp_surface_proxy->SetRect(visual_transform->MapRect(
       gfx::Rect(params.quad_rect.origin(), on_screen_size)));
 
+  dcomp_surface_proxy->SetProtectedVideoType(params.protected_video_type);
+
   // If |dcomp_surface_proxy| size is {1, 1}, the texture was initialized
   // without knowledge of output size; reset |content_| so it's not added to the
   // visual tree.
@@ -1649,7 +1626,7 @@
 
   DCHECK(!swap_chain_size.IsEmpty());
   swap_chain_size_ = swap_chain_size;
-  protected_video_type_ = protected_video_type;
+  swap_chain_protected_video_type_ = protected_video_type;
   gpu_vendor_id_ = 0;
 
   ReleaseSwapChainResources();
@@ -1693,9 +1670,6 @@
     desc.Flags |= DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED;
   desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
 
-  const std::string kSwapChainCreationResultByFormatUmaPrefix =
-      "GPU.DirectComposition.SwapChainCreationResult2.";
-
   const std::string kSwapChainCreationResultByVideoTypeUmaPrefix =
       "GPU.DirectComposition.SwapChainCreationResult3.";
   const std::string protected_video_type_string =
@@ -1709,9 +1683,6 @@
         &swap_chain_);
     failed_to_create_yuv_swapchain_ = FAILED(hr);
 
-    base::UmaHistogramSparse(kSwapChainCreationResultByFormatUmaPrefix +
-                                 DxgiFormatToString(swap_chain_format),
-                             hr);
     base::UmaHistogramSparse(kSwapChainCreationResultByVideoTypeUmaPrefix +
                                  protected_video_type_string,
                              hr);
@@ -1745,9 +1716,6 @@
         d3d11_device_.Get(), swap_chain_handle_.Get(), &desc, nullptr,
         &swap_chain_);
 
-    base::UmaHistogramSparse(kSwapChainCreationResultByFormatUmaPrefix +
-                                 DxgiFormatToString(swap_chain_format),
-                             hr);
     base::UmaHistogramSparse(kSwapChainCreationResultByVideoTypeUmaPrefix +
                                  protected_video_type_string,
                              hr);
diff --git a/ui/gl/swap_chain_presenter.h b/ui/gl/swap_chain_presenter.h
index 5331fe25..6f2a53c 100644
--- a/ui/gl/swap_chain_presenter.h
+++ b/ui/gl/swap_chain_presenter.h
@@ -64,19 +64,6 @@
     kMaxValue = kBindAndVideoProcessorBlit,
   };
 
-  // Mapped to DecodeSwapChainNotUsedReason UMA enum.  Do not remove or remap
-  // existing entries.
-  enum class DecodeSwapChainNotUsedReason {
-    kSoftwareFrame = 0,
-    kNv12NotSupported = 1,
-    kFailedToPresent = 2,
-    kNonDecoderTexture = 3,
-    kSharedTexture = 4,
-    kIncompatibleTransform = 5,
-    kUnitaryTextureArray = 6,
-    kMaxValue = kUnitaryTextureArray,
-  };
-
   // This keeps track of whether the previous 30 frames used Overlays or GPU
   // composition to present.
   class PresentationHistory {
@@ -247,7 +234,7 @@
 
   // Whether the current swap chain is presenting protected video, software
   // or hardware protection.
-  gfx::ProtectedVideoType protected_video_type_ =
+  gfx::ProtectedVideoType swap_chain_protected_video_type_ =
       gfx::ProtectedVideoType::kClear;
 
   // Presentation history to track if swap chain was composited or used hardware
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 69a2874e..5eb9668 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -32,8 +32,6 @@
     "common/wayland_object.h",
     "common/wayland_util.cc",
     "common/wayland_util.h",
-    "gpu/drm_render_node_path_finder.cc",
-    "gpu/drm_render_node_path_finder.h",
     "gpu/gl_surface_egl_readback_wayland.cc",
     "gpu/gl_surface_egl_readback_wayland.h",
     "gpu/gl_surface_wayland.cc",
@@ -357,6 +355,8 @@
     sources += [
       "gpu/drm_render_node_handle.cc",
       "gpu/drm_render_node_handle.h",
+      "gpu/drm_render_node_path_finder.cc",
+      "gpu/drm_render_node_path_finder.h",
       "gpu/gbm_pixmap_wayland.cc",
       "gpu/gbm_pixmap_wayland.h",
       "gpu/gbm_surfaceless_wayland.cc",
diff --git a/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc b/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc
index b520db32..cdce6ae 100644
--- a/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc
+++ b/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc
@@ -13,10 +13,7 @@
 
 #include "base/files/scoped_file.h"
 #include "base/strings/stringprintf.h"
-
-#if defined(WAYLAND_GBM)
 #include "ui/gfx/linux/scoped_gbm_device.h"  // nogncheck
-#endif
 
 namespace ui {
 
@@ -62,13 +59,11 @@
     if (drm_fd.get() < 0)
       continue;
 
-#if defined(WAYLAND_GBM)
     // In case the first node /dev/dri/renderD128 can be opened but fails to
     // create gbm device on certain driver (E.g. PowerVR). Skip such paths.
     ScopedGbmDevice device(gbm_create_device(drm_fd.get()));
     if (!device)
       continue;
-#endif
 
     drm_render_node_path_ = base::FilePath(dri_render_node);
     break;
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 40f2afe..9054783 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -33,7 +33,6 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/common/features.h"
 #include "ui/ozone/platform/wayland/common/wayland_util.h"
-#include "ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_overlay_manager.h"
@@ -73,6 +72,10 @@
 #include "ui/ozone/platform/wayland/host/wayland_cursor_factory.h"
 #endif
 
+#if defined(WAYLAND_GBM)
+#include "ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.h"
+#endif
+
 namespace ui {
 
 namespace {
@@ -184,6 +187,7 @@
 
   bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
                                      gfx::BufferUsage usage) const override {
+#if defined(WAYLAND_GBM)
     // If there is no drm render node device available, native pixmaps are not
     // supported.
     if (path_finder_.GetDrmRenderNodePath().empty())
@@ -196,6 +200,9 @@
 
     return gfx::ClientNativePixmapDmaBuf::IsConfigurationSupported(format,
                                                                    usage);
+#else
+    return false;
+#endif
   }
 
   bool ShouldUseCustomFrame() override {
@@ -428,9 +435,11 @@
   // framework.
   wl::BufferFormatsWithModifiersMap supported_buffer_formats_;
 
+#if defined(WAYLAND_GBM)
   // This is used both in the gpu and browser processes to find out if a drm
   // render node is available.
   DrmRenderNodePathFinder path_finder_;
+#endif
 
 #if BUILDFLAG(USE_GTK)
   std::unique_ptr<LinuxUiDelegateWayland> gtk_ui_platform_;