diff --git a/DEPS b/DEPS
index 8ea0118..5972b80d 100644
--- a/DEPS
+++ b/DEPS
@@ -314,7 +314,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': 'aa208c8a2d60b087ef74d35737b037cfe85a4fc4',
+  'skia_revision': 'd0d2b7042bb92519743204405063f6cb42d9ae77',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -322,7 +322,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': '823de3a30c4fccae5f67aa99f4ee9f4847e3b2e3',
+  'angle_revision': '0ef565c50e043c90721aa681760b6ef002e04c88',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -405,7 +405,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'fc8a5ad2e2444574f74c2d89e30b9e737c95db62',
+  'devtools_frontend_revision': 'ff4b64d4cfca098622240acfbf1b67f86baa4222',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -837,7 +837,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '446cc4c9eea2d0582c8e0900c4a73e4b9a38d1dc',
+    '0abd043e381553ee9ddcc95e795c255920429aa9',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1276,13 +1276,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'a1cfc693af3505461fea2a59eaf484720c897c4f',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3dce403ca3903542176cd6e37bcc2bd828424bb4',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '7c32916a74a355986e732ab6daba4435b337242a',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'fcf4730b69ef06a8b17f1ab0c7076d2bbcf7fe2b',
     'condition': 'checkout_src_internal',
   },
 
@@ -1740,7 +1740,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '09a4f3ec842a8932341b195c5b01e141c8a16eb7',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + 'ba66153da90641c95731613db6582a5b64e6d847',
+    Var('chromium_git') + '/openscreen' + '@' + '4ec042afaf420eea2d6f2cfabfbb71b8810ea7a8',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '58a00cf85c39ad5ec4dc43a769624e420c06179a',
@@ -1896,7 +1896,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@aa121378c102bf27e8995258aac6b90eaba712e4',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@33e5568092a08dd3cd80fe7a56560abea5976ea8',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'e87036508bb156f9986ea959323de1869e328f58',
@@ -1933,7 +1933,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '3e71f3b643f8095babbd46cf4e7d34e4f1ddf7a8',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '4fc748388076ebf618edb742505be93892e4057a',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '2ee990a4cb91b41491f83b52c9520476b18a9fd8',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '8284f2b4e8670529d039a8b6c73ec5f1d760bd21',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 11ffa2ea..3f2ca9e2 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -4311,6 +4311,8 @@
     "test/test_widget_builder.h",
     "test/test_window_builder.cc",
     "test/test_window_builder.h",
+    "test/time_of_day_test_util.cc",
+    "test/time_of_day_test_util.h",
     "test/toplevel_window.cc",
     "test/toplevel_window.h",
     "test/ui_controls_ash.cc",
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 7bb01c2..9831d32 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -1279,7 +1279,8 @@
   widget->Activate();
   widget->GetNativeView()->SetProperty(
       aura::client::kResizeBehaviorKey,
-      aura::client::kResizeBehaviorCanMaximize);
+      aura::client::kResizeBehaviorCanMaximize |
+          aura::client::kResizeBehaviorCanFullscreen);
 
   ui::test::EventGenerator* generator = GetEventGenerator();
   WindowState* window_state = WindowState::Get(widget->GetNativeView());
diff --git a/ash/components/arc/power/arc_power_bridge.cc b/ash/components/arc/power/arc_power_bridge.cc
index 5010b71..af836e09 100644
--- a/ash/components/arc/power/arc_power_bridge.cc
+++ b/ash/components/arc/power/arc_power_bridge.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <utility>
 
-#include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "ash/components/arc/arc_util.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
 #include "ash/shell.h"
@@ -15,7 +14,6 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
-#include "base/memory/singleton.h"
 #include "base/metrics/histogram_functions.h"
 #include "chromeos/ash/components/dbus/patchpanel/patchpanel_client.h"
 #include "chromeos/dbus/power/power_policy_controller.h"
@@ -33,27 +31,13 @@
 // order to prevent spammy brightness updates.
 constexpr base::TimeDelta kNotifyBrightnessDelay = base::Milliseconds(200);
 
-// Singleton factory for ArcPowerBridge.
-class ArcPowerBridgeFactory
-    : public internal::ArcBrowserContextKeyedServiceFactoryBase<
-          ArcPowerBridge,
-          ArcPowerBridgeFactory> {
- public:
-  // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
-  static constexpr const char* kName = "ArcPowerBridgeFactory";
-
-  static ArcPowerBridgeFactory* GetInstance() {
-    return base::Singleton<ArcPowerBridgeFactory>::get();
-  }
-
- private:
-  friend base::DefaultSingletonTraits<ArcPowerBridgeFactory>;
-  ArcPowerBridgeFactory() = default;
-  ~ArcPowerBridgeFactory() override = default;
-};
-
 }  // namespace
 
+// static
+ArcPowerBridgeFactory* ArcPowerBridgeFactory::GetInstance() {
+  return base::Singleton<ArcPowerBridgeFactory>::get();
+}
+
 // WakeLockRequestor requests a wake lock from the device service in response
 // to wake lock requests of a given type from Android. A count is kept of
 // outstanding Android requests so that only a single actual wake lock is used.
@@ -138,6 +122,9 @@
 }
 
 ArcPowerBridge::~ArcPowerBridge() {
+  for (auto& observer : observer_list_) {
+    observer.OnWillDestroyArcPowerBridge();
+  }
   arc_bridge_service_->power()->RemoveObserver(this);
   arc_bridge_service_->power()->SetHost(nullptr);
 }
@@ -261,6 +248,9 @@
     LOG(ERROR) << "Failed to resume arcvm: " << reply.value().failure_reason();
     return;
   }
+  for (auto& observer : observer_list_) {
+    observer.OnVmResumed();
+  }
   DispatchAndroidResume();
 }
 
diff --git a/ash/components/arc/power/arc_power_bridge.h b/ash/components/arc/power/arc_power_bridge.h
index 95f60c2..971ec336 100644
--- a/ash/components/arc/power/arc_power_bridge.h
+++ b/ash/components/arc/power/arc_power_bridge.h
@@ -9,11 +9,13 @@
 #include <memory>
 #include <string>
 
+#include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "ash/components/arc/mojom/anr.mojom.h"
 #include "ash/components/arc/mojom/power.mojom.h"
 #include "ash/components/arc/session/arc_service_manager.h"
 #include "ash/components/arc/session/connection_observer.h"
 #include "base/memory/raw_ptr.h"
+#include "base/memory/singleton.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -33,6 +35,24 @@
 namespace arc {
 
 class ArcBridgeService;
+class ArcPowerBridge;  // So we can declare the factory first.
+
+// Singleton factory for ArcPowerBridge.
+class ArcPowerBridgeFactory
+    : public internal::ArcBrowserContextKeyedServiceFactoryBase<
+          ArcPowerBridge,
+          ArcPowerBridgeFactory> {
+ public:
+  // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
+  static constexpr const char* kName = "ArcPowerBridgeFactory";
+
+  static ArcPowerBridgeFactory* GetInstance();
+
+ private:
+  friend base::DefaultSingletonTraits<ArcPowerBridgeFactory>;
+  ArcPowerBridgeFactory() = default;
+  ~ArcPowerBridgeFactory() override = default;
+};
 
 // ARC Power Client sets power management policy based on requests from
 // ARC instances.
@@ -47,6 +67,13 @@
     // Notifies that wakefulness mode is changed.
     virtual void OnWakefulnessChanged(mojom::WakefulnessMode mode) {}
     virtual void OnPreAnr(mojom::AnrType type) {}
+
+    // Notifies about resume state of the underlying VM (ARCVM-exclusive).
+    // ARC Container does not communicate with CrosVM, and it doesn't
+    // instantiate services that care about this event.
+    virtual void OnVmResumed() {}
+
+    virtual void OnWillDestroyArcPowerBridge() {}
   };
 
   // Returns singleton instance for the given BrowserContext,
diff --git a/ash/system/geolocation/geolocation_controller.cc b/ash/system/geolocation/geolocation_controller.cc
index 333060a..38861a3 100644
--- a/ash/system/geolocation/geolocation_controller.cc
+++ b/ash/system/geolocation/geolocation_controller.cc
@@ -295,11 +295,15 @@
   if (!geoposition_) {
     VLOG(1) << "Invalid geoposition. Using default time for "
             << (sunrise ? "sunrise." : "sunset.");
-    return TimeOfDay(sunrise ? kDefaultSunriseTimeOffsetMinutes
-                             : kDefaultSunsetTimeOffsetMinutes)
-        .SetClock(clock_)
-        .SetLocalTimeConverter(local_time_converter_)
-        .ToTimeToday();
+    const absl::optional<base::Time> default_value =
+        TimeOfDay(sunrise ? kDefaultSunriseTimeOffsetMinutes
+                          : kDefaultSunsetTimeOffsetMinutes)
+            .SetClock(clock_)
+            .SetLocalTimeConverter(local_time_converter_)
+            .ToTimeToday();
+    // TODO(b/294437057): Change this method's return value to return a type
+    // that makes this failure more obvious to the caller.
+    return default_value.value_or(base::Time());
   }
 
   icu::CalendarAstronomer astro(geoposition_->longitude,
@@ -310,13 +314,18 @@
   // See the documentation of icu::CalendarAstronomer::getSunRiseSet().
   // Note that the icu calendar works with milliseconds since epoch, and
   // base::Time::FromDoubleT() / ToDoubleT() work with seconds since epoch.
-  const double midday_today_sec =
+  const absl::optional<base::Time> midday_today =
       TimeOfDay(12 * 60)
           .SetClock(clock_)
           .SetLocalTimeConverter(local_time_converter_)
-          .ToTimeToday()
-          .ToDoubleT();
-  astro.setTime(midday_today_sec * 1000.0);
+          .ToTimeToday();
+  if (!midday_today) {
+    // TODO(b/294437057): Change this method's return value to return a type
+    // that makes this failure more obvious to the caller.
+    return base::Time();
+  }
+
+  astro.setTime(midday_today->ToDoubleT() * 1000.0);
   const double sun_rise_set_ms = astro.getSunRiseSet(sunrise);
   // If there is 24 hours of daylight or darkness, `CalendarAstronomer` returns
   // a very large negative value. Any timestamp before or at the epoch
diff --git a/ash/system/geolocation/geolocation_controller_unittest.cc b/ash/system/geolocation/geolocation_controller_unittest.cc
index 49cae2e..c23fcf8d 100644
--- a/ash/system/geolocation/geolocation_controller_unittest.cc
+++ b/ash/system/geolocation/geolocation_controller_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/system/geolocation/test_geolocation_url_loader_factory.h"
 #include "ash/system/time/time_of_day.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/time_of_day_test_util.h"
 #include "ash/test_shell_delegate.h"
 #include "base/check.h"
 #include "base/memory/raw_ptr.h"
@@ -392,9 +393,9 @@
   // If geoposition is unset, the controller should return the default sunset
   // and sunrise time .
   EXPECT_EQ(controller()->GetSunsetTime(),
-            TimeOfDay(kDefaultSunsetTimeOffsetMinutes).ToTimeToday());
+            ToTimeToday(TimeOfDay(kDefaultSunsetTimeOffsetMinutes)));
   EXPECT_EQ(controller()->GetSunriseTime(),
-            TimeOfDay(kDefaultSunriseTimeOffsetMinutes).ToTimeToday());
+            ToTimeToday(TimeOfDay(kDefaultSunriseTimeOffsetMinutes)));
 }
 
 // Tests the behavior when there is a valid geoposition, sunrise and sunset
@@ -531,14 +532,14 @@
   // Switching to user 1 should ignore the current geoposition since it's
   // a cached value from user 2's prefs rather than a newly-updated value.
   SwitchActiveUser(kUser1Email);
-  EXPECT_EQ(controller()->GetSunsetTime(),
-            TimeOfDay(kDefaultSunsetTimeOffsetMinutes)
-                .SetClock(test_clock())
-                .ToTimeToday());
-  EXPECT_EQ(controller()->GetSunriseTime(),
-            TimeOfDay(kDefaultSunriseTimeOffsetMinutes)
-                .SetClock(test_clock())
-                .ToTimeToday());
+  EXPECT_EQ(
+      controller()->GetSunsetTime(),
+      ToTimeToday(
+          TimeOfDay(kDefaultSunsetTimeOffsetMinutes).SetClock(test_clock())));
+  EXPECT_EQ(
+      controller()->GetSunriseTime(),
+      ToTimeToday(
+          TimeOfDay(kDefaultSunriseTimeOffsetMinutes).SetClock(test_clock())));
 
   // Now simulate receiving a live geoposition update.
   Geoposition position;
diff --git a/ash/system/night_light/night_light_controller_impl.cc b/ash/system/night_light/night_light_controller_impl.cc
index cf13cba..8e59b37 100644
--- a/ash/system/night_light/night_light_controller_impl.cc
+++ b/ash/system/night_light/night_light_controller_impl.cc
@@ -138,8 +138,15 @@
     if (!HasGeoposition()) {
       LOG(ERROR) << "Invalid geoposition. Using default time for "
                  << (sunrise ? "sunrise." : "sunset.");
-      return sunrise ? TimeOfDay(kDefaultEndTimeOffsetMinutes).ToTimeToday()
-                     : TimeOfDay(kDefaultStartTimeOffsetMinutes).ToTimeToday();
+      return sunrise ? TimeOfDay(kDefaultEndTimeOffsetMinutes)
+                           .ToTimeToday()
+                           // TODO(b/289276024): `ToTimeToday()` failures will
+                           // be handled properly when night light has migrated
+                           // to use `GeolocationController`.
+                           .value_or(base::Time())
+                     : TimeOfDay(kDefaultStartTimeOffsetMinutes)
+                           .ToTimeToday()
+                           .value_or(base::Time());
     }
 
     icu::CalendarAstronomer astro(geoposition_->longitude,
@@ -151,7 +158,7 @@
     // Note that the icu calendar works with milliseconds since epoch, and
     // base::Time::FromDoubleT() / ToDoubleT() work with seconds since epoch.
     const double midday_today_sec =
-        TimeOfDay(12 * 60).ToTimeToday().ToDoubleT();
+        TimeOfDay(12 * 60).ToTimeToday().value_or(base::Time()).ToDoubleT();
     astro.setTime(midday_today_sec * 1000.0);
     const double sun_rise_set_ms = astro.getSunRiseSet(sunrise);
     return base::Time::FromDoubleT(sun_rise_set_ms / 1000.0);
@@ -1064,7 +1071,8 @@
 
     case ScheduleType::kCustom:
       RefreshScheduleTimer(
-          GetCustomStartTime().ToTimeToday(), GetCustomEndTime().ToTimeToday(),
+          GetCustomStartTime().ToTimeToday().value_or(base::Time()),
+          GetCustomEndTime().ToTimeToday().value_or(base::Time()),
           did_schedule_change, keep_manual_toggles_during_schedules);
       return;
   }
diff --git a/ash/system/night_light/night_light_controller_unittest.cc b/ash/system/night_light/night_light_controller_unittest.cc
index 8d0f8df..2c07185 100644
--- a/ash/system/night_light/night_light_controller_unittest.cc
+++ b/ash/system/night_light/night_light_controller_unittest.cc
@@ -20,6 +20,7 @@
 #include "ash/system/time/time_of_day.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
+#include "ash/test/time_of_day_test_util.h"
 #include "ash/test_shell_delegate.h"
 #include "base/command_line.h"
 #include "base/functional/bind.h"
@@ -154,9 +155,9 @@
   ~TestDelegate() override = default;
 
   void SetFakeNow(base::Time time) { fake_now_ = time; }
-  void SetFakeNow(TimeOfDay time) { fake_now_ = time.ToTimeToday(); }
-  void SetFakeSunset(TimeOfDay time) { fake_sunset_ = time.ToTimeToday(); }
-  void SetFakeSunrise(TimeOfDay time) { fake_sunrise_ = time.ToTimeToday(); }
+  void SetFakeNow(TimeOfDay time) { fake_now_ = ToTimeToday(time); }
+  void SetFakeSunset(TimeOfDay time) { fake_sunset_ = ToTimeToday(time); }
+  void SetFakeSunrise(TimeOfDay time) { fake_sunrise_ = ToTimeToday(time); }
 
   // ash::NightLightControllerImpl::Delegate
   base::Time GetNow() const override { return fake_now_; }
@@ -814,8 +815,8 @@
   EXPECT_TRUE(controller->is_current_geoposition_from_cache());
   const TimeOfDay kSunset2{kFakePosition2_SunsetOffset};
   const TimeOfDay kSunrise2{kFakePosition2_SunriseOffset};
-  EXPECT_EQ(delegate()->GetSunsetTime(), kSunset2.ToTimeToday());
-  EXPECT_EQ(delegate()->GetSunriseTime(), kSunrise2.ToTimeToday());
+  EXPECT_EQ(delegate()->GetSunsetTime(), ToTimeToday(kSunset2));
+  EXPECT_EQ(delegate()->GetSunriseTime(), ToTimeToday(kSunrise2));
 
   // Store fake geoposition 1 in user 1's prefs.
   user1_pref_service()->SetDouble(prefs::kNightLightCachedLatitude,
@@ -831,16 +832,16 @@
   EXPECT_TRUE(controller->is_current_geoposition_from_cache());
   const TimeOfDay kSunset1{kFakePosition1_SunsetOffset};
   const TimeOfDay kSunrise1{kFakePosition1_SunriseOffset};
-  EXPECT_EQ(delegate()->GetSunsetTime(), kSunset1.ToTimeToday());
-  EXPECT_EQ(delegate()->GetSunriseTime(), kSunrise1.ToTimeToday());
+  EXPECT_EQ(delegate()->GetSunsetTime(), ToTimeToday(kSunset1));
+  EXPECT_EQ(delegate()->GetSunriseTime(), ToTimeToday(kSunrise1));
 
   // Now simulate receiving a geoposition update of fake geoposition 2.
   controller->SetCurrentGeoposition(NightLightController::SimpleGeoposition{
       kFakePosition2_Latitude, kFakePosition2_Longitude});
   EXPECT_TRUE(delegate()->HasGeoposition());
   EXPECT_FALSE(controller->is_current_geoposition_from_cache());
-  EXPECT_EQ(delegate()->GetSunsetTime(), kSunset2.ToTimeToday());
-  EXPECT_EQ(delegate()->GetSunriseTime(), kSunrise2.ToTimeToday());
+  EXPECT_EQ(delegate()->GetSunsetTime(), ToTimeToday(kSunset2));
+  EXPECT_EQ(delegate()->GetSunriseTime(), ToTimeToday(kSunrise2));
 
   // Update user 2's prefs with fake geoposition 1.
   user2_pref_service()->SetDouble(prefs::kNightLightCachedLatitude,
@@ -853,8 +854,8 @@
   SwitchActiveUser(kUser2Email);
   EXPECT_TRUE(delegate()->HasGeoposition());
   EXPECT_FALSE(controller->is_current_geoposition_from_cache());
-  EXPECT_EQ(delegate()->GetSunsetTime(), kSunset2.ToTimeToday());
-  EXPECT_EQ(delegate()->GetSunriseTime(), kSunrise2.ToTimeToday());
+  EXPECT_EQ(delegate()->GetSunsetTime(), ToTimeToday(kSunset2));
+  EXPECT_EQ(delegate()->GetSunriseTime(), ToTimeToday(kSunrise2));
 
   // Clear all cached geoposition prefs for all users, just to make sure getting
   // a new geoposition with persist it for all users not just the active one.
@@ -868,8 +869,8 @@
       kFakePosition1_Latitude, kFakePosition1_Longitude});
   EXPECT_TRUE(delegate()->HasGeoposition());
   EXPECT_FALSE(controller->is_current_geoposition_from_cache());
-  EXPECT_EQ(delegate()->GetSunsetTime(), kSunset1.ToTimeToday());
-  EXPECT_EQ(delegate()->GetSunriseTime(), kSunrise1.ToTimeToday());
+  EXPECT_EQ(delegate()->GetSunsetTime(), ToTimeToday(kSunset1));
+  EXPECT_EQ(delegate()->GetSunriseTime(), ToTimeToday(kSunrise1));
   EXPECT_EQ(kFakePosition1_Latitude,
             user1_pref_service()->GetDouble(prefs::kNightLightCachedLatitude));
   EXPECT_EQ(kFakePosition1_Longitude,
@@ -1101,12 +1102,11 @@
     bool user_1_expected_status;
     bool user_2_expected_status;
   } kTestCases[] = {
-      {MakeTimeOfDay(2, kPM).ToTimeToday(), false, false},
-      {MakeTimeOfDay(4, kPM).ToTimeToday(), true, false},
-      {MakeTimeOfDay(7, kPM).ToTimeToday(), true, true},
-      {MakeTimeOfDay(10, kPM).ToTimeToday(), false, true},
-      {MakeTimeOfDay(9, kAM).ToTimeToday() +
-           base::Days(1),  // 9:00 AM tomorrow.
+      {ToTimeToday(MakeTimeOfDay(2, kPM)), false, false},
+      {ToTimeToday(MakeTimeOfDay(4, kPM)), true, false},
+      {ToTimeToday(MakeTimeOfDay(7, kPM)), true, true},
+      {ToTimeToday(MakeTimeOfDay(10, kPM)), false, true},
+      {ToTimeToday(MakeTimeOfDay(9, kAM)) + base::Days(1),  // 9:00 AM tomorrow.
        false, false},
   };
 
diff --git a/ash/system/night_light/night_light_feature_pod_controller.cc b/ash/system/night_light/night_light_feature_pod_controller.cc
index bcdf78bd..4d352b50 100644
--- a/ash/system/night_light/night_light_feature_pod_controller.cc
+++ b/ash/system/night_light/night_light_feature_pod_controller.cc
@@ -146,11 +146,16 @@
               ? IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_ON_STATE_SUNSET_TO_SUNRISE_SCHEDULED
               : IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_OFF_STATE_SUNSET_TO_SUNRISE_SCHEDULED);
     case NightLightController::ScheduleType::kCustom:
-      const TimeOfDay time = is_enabled ? controller->GetCustomEndTime()
+      const TimeOfDay time_of_day = is_enabled
+                                        ? controller->GetCustomEndTime()
                                         : controller->GetCustomStartTime();
+      const absl::optional<base::Time> time = time_of_day.ToTimeToday();
+      if (!time) {
+        return std::u16string();
+      }
       const std::u16string time_str =
           base::TimeFormatTimeOfDayWithHourClockType(
-              time.ToTimeToday(),
+              *time,
               Shell::Get()->system_tray_model()->clock()->hour_clock_type(),
               base::kKeepAmPm);
       return is_enabled
diff --git a/ash/system/night_light/night_light_feature_pod_controller_unittest.cc b/ash/system/night_light/night_light_feature_pod_controller_unittest.cc
index 4a75b0d6..83ea20ad 100644
--- a/ash/system/night_light/night_light_feature_pod_controller_unittest.cc
+++ b/ash/system/night_light/night_light_feature_pod_controller_unittest.cc
@@ -16,6 +16,7 @@
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/system/unified/unified_system_tray_bubble.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/time_of_day_test_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -184,11 +185,11 @@
   auto* clock_model = Shell::Get()->system_tray_model()->clock();
   const std::u16string start_time_str =
       base::TimeFormatTimeOfDayWithHourClockType(
-          controller->GetCustomStartTime().ToTimeToday(),
+          ToTimeToday(controller->GetCustomStartTime()),
           clock_model->hour_clock_type(), base::kKeepAmPm);
   const std::u16string end_time_str =
       base::TimeFormatTimeOfDayWithHourClockType(
-          controller->GetCustomEndTime().ToTimeToday(),
+          ToTimeToday(controller->GetCustomEndTime()),
           clock_model->hour_clock_type(), base::kKeepAmPm);
   const std::u16string sublabel_on = l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_ON_STATE_CUSTOM_SCHEDULED, end_time_str);
diff --git a/ash/system/scheduled_feature/scheduled_feature.cc b/ash/system/scheduled_feature/scheduled_feature.cc
index 66c217d6..c19b3ff 100644
--- a/ash/system/scheduled_feature/scheduled_feature.cc
+++ b/ash/system/scheduled_feature/scheduled_feature.cc
@@ -337,7 +337,10 @@
 
 void ScheduledFeature::Refresh(bool did_schedule_change,
                                bool keep_manual_toggles_during_schedules) {
-  switch (GetScheduleType()) {
+  absl::optional<base::Time> start_time;
+  absl::optional<base::Time> end_time;
+  const ScheduleType schedule_type = GetScheduleType();
+  switch (schedule_type) {
     case ScheduleType::kNone:
       timer_->Stop();
       RefreshFeatureState();
@@ -345,25 +348,44 @@
           GetCheckpointForEnabledState(GetEnabled(), ScheduleType::kNone));
       return;
     case ScheduleType::kSunsetToSunrise: {
-      base::Time sunrise_time = geolocation_controller_->GetSunriseTime();
-      base::Time sunset_time = geolocation_controller_->GetSunsetTime();
+      const base::Time sunrise_time = geolocation_controller_->GetSunriseTime();
+      const base::Time sunset_time = geolocation_controller_->GetSunsetTime();
       if (sunrise_time == GeolocationController::kNoSunRiseSet ||
           sunset_time == GeolocationController::kNoSunRiseSet) {
         // Simply disable the feature in this corner case. Since sunset and
         // sunrise are exactly the same, there is no time for it to be enabled.
-        sunrise_time = clock_->Now();
-        sunset_time = sunrise_time;
+        start_time = clock_->Now();
+        end_time = start_time;
+      } else if (!sunrise_time.is_null() && !sunset_time.is_null()) {
+        start_time = sunset_time;
+        end_time = sunrise_time;
+      } else {
+        // Sunrise or sunset is temporarily unavailable. Leave `start_time` and
+        // `end_time` unset.
       }
-      RefreshScheduleTimer(sunset_time, sunrise_time, did_schedule_change,
-                           keep_manual_toggles_during_schedules);
-      return;
+      break;
     }
     case ScheduleType::kCustom:
-      RefreshScheduleTimer(
-          GetCustomStartTime().ToTimeToday(), GetCustomEndTime().ToTimeToday(),
-          did_schedule_change, keep_manual_toggles_during_schedules);
-      return;
+      start_time = GetCustomStartTime().ToTimeToday();
+      end_time = GetCustomEndTime().ToTimeToday();
+      break;
   }
+
+  // b/285187343: Timestamps can legitimately be null if getting local time
+  // fails.
+  if (!start_time || !end_time) {
+    LOG(ERROR) << "Received null start/end times at " << clock_->Now();
+    ScheduleNextRefreshRetry(keep_manual_toggles_during_schedules);
+    // Best effort to still make `current_checkpoint_` as accurate as possible
+    // before exiting and not be in an inconsistent state. The next successful
+    // `Refresh()` will make `current_checkpoint_` 100% accurate again.
+    SetCurrentCheckpoint(
+        GetCheckpointForEnabledState(GetEnabled(), schedule_type));
+    return;
+  }
+
+  RefreshScheduleTimer(*start_time, *end_time, did_schedule_change,
+                       keep_manual_toggles_during_schedules);
 }
 
 // The `ScheduleCheckpoint` usage in this method does not directly apply
@@ -384,20 +406,6 @@
   }
 
   const base::Time now = clock_->Now();
-  // b/285187343: Timestamps can legitimately be null if getting local time
-  // fails.
-  if (start_time.is_null() || end_time.is_null()) {
-    LOG(ERROR) << "Received null timestamps. start_time=" << start_time
-               << "end_time=" << end_time << " now=" << now;
-    ScheduleNextRefreshRetry(keep_manual_toggles_during_schedules);
-    // Best effort to still make `current_checkpoint_` as accurate as possible
-    // before exiting and not be in an inconsistent state. The next successful
-    // `Refresh()` will make `current_checkpoint_` 100% accurate again.
-    SetCurrentCheckpoint(
-        GetCheckpointForEnabledState(GetEnabled(), schedule_type));
-    return;
-  }
-
   const schedule_utils::Position schedule_position =
       schedule_utils::GetCurrentPosition(now, start_time, end_time,
                                          schedule_type);
diff --git a/ash/system/scheduled_feature/scheduled_feature_unittest.cc b/ash/system/scheduled_feature/scheduled_feature_unittest.cc
index 654ffca..1cef7e3 100644
--- a/ash/system/scheduled_feature/scheduled_feature_unittest.cc
+++ b/ash/system/scheduled_feature/scheduled_feature_unittest.cc
@@ -27,6 +27,7 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test/failing_local_time_converter.h"
+#include "ash/test/time_of_day_test_util.h"
 #include "ash/test_shell_delegate.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
@@ -350,7 +351,7 @@
   // 1) now = 2 PM time_of_day = 5 PM, advances 3 hours
   // 2) now = 7 PM time_of_day = 5 PM, advances 22 hours (the next day)
   void FastForwardTo(TimeOfDay time_of_day) {
-    base::Time target_time = time_of_day.SetClock(this).ToTimeToday();
+    base::Time target_time = ToTimeToday(time_of_day.SetClock(this));
     const base::Time now = Now();
     if (target_time < now) {
       target_time += base::Days(1);
diff --git a/ash/system/time/time_of_day.cc b/ash/system/time/time_of_day.cc
index 35cbfa77..40fcd39 100644
--- a/ash/system/time/time_of_day.cc
+++ b/ash/system/time/time_of_day.cc
@@ -44,7 +44,7 @@
   return *this;
 }
 
-base::Time TimeOfDay::ToTimeToday() const {
+absl::optional<base::Time> TimeOfDay::ToTimeToday() const {
   base::Time::Exploded now;
   GetLocalTimeConverter().LocalExplode(GetNow(), &now);
   // Per the `LocalExplode()` API:
@@ -52,7 +52,7 @@
   // assigned invalid values. Use Exploded::HasValidValues() to confirm a
   // successful conversion."
   if (!now.HasValidValues()) {
-    return base::Time();
+    return absl::nullopt;
   }
   now.hour = (offset_minutes_from_zero_hour_ / 60) % 24;
   now.minute = offset_minutes_from_zero_hour_ % 60;
@@ -63,15 +63,19 @@
     return result;
   }
 
-  // Daylight saving time can cause FromLocalExploded() to fail on the
+  // Known failure cases:
+  // 1) Daylight saving time can cause FromLocalExploded() to fail on the
   // transition day in the spring when TimeOfDay == 2:30 AM, and the time goes
   // instantaneously from 1:59 AM 3:00 AM. In this very rare case, it's OK for
   // this function to fail.
-  return base::Time();
+  // 2) crbug.com/1307913.
+  return absl::nullopt;
 }
 
 std::string TimeOfDay::ToString() const {
-  return base::UTF16ToUTF8(base::TimeFormatTimeOfDay(ToTimeToday()));
+  const absl::optional<base::Time> time_today = ToTimeToday();
+  return time_today ? base::UTF16ToUTF8(base::TimeFormatTimeOfDay(*time_today))
+                    : "unknown";
 }
 
 base::Time TimeOfDay::GetNow() const {
diff --git a/ash/system/time/time_of_day.h b/ash/system/time/time_of_day.h
index cea64a6..7c4a56f 100644
--- a/ash/system/time/time_of_day.h
+++ b/ash/system/time/time_of_day.h
@@ -13,6 +13,7 @@
 #include "base/memory/raw_ptr_exclusion.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
 
@@ -53,11 +54,12 @@
   TimeOfDay& SetLocalTimeConverter(
       const LocalTimeConverter* local_time_converter);
 
-  // Converts to an actual point in time today. If this fail for some reason,
-  // base::Time() will be returned.
-  base::Time ToTimeToday() const;
+  // Converts to an actual point in time today. If this fails for some reason,
+  // `absl::nullopt` will be returned. Otherwise, always returns a valid
+  // non-null timestamp.
+  absl::optional<base::Time> ToTimeToday() const;
 
-  // Converts to a string in the format "3:07 PM".
+  // Converts to a string in the format "3:07 PM". Only for debugging use.
   std::string ToString() const;
 
  private:
diff --git a/ash/system/time/time_of_day_unittest.cc b/ash/system/time/time_of_day_unittest.cc
index cff96b3..5e6a7de 100644
--- a/ash/system/time/time_of_day_unittest.cc
+++ b/ash/system/time/time_of_day_unittest.cc
@@ -95,7 +95,7 @@
   FailingLocalTimeConverter failing_local_time_converter;
   TimeOfDay time_of_day =
       TimeOfDay(12 * 60).SetLocalTimeConverter(&failing_local_time_converter);
-  EXPECT_TRUE(time_of_day.ToTimeToday().is_null());
+  EXPECT_FALSE(time_of_day.ToTimeToday());
 }
 
 }  // namespace
diff --git a/ash/test/test_window_builder.cc b/ash/test/test_window_builder.cc
index c8978f5..4733c90 100644
--- a/ash/test/test_window_builder.cc
+++ b/ash/test/test_window_builder.cc
@@ -89,7 +89,8 @@
 TestWindowBuilder& TestWindowBuilder::AllowAllWindowStates() {
   DCHECK(!built_);
   init_properties_.SetProperty(aura::client::kResizeBehaviorKey,
-                               aura::client::kResizeBehaviorCanMaximize |
+                               aura::client::kResizeBehaviorCanFullscreen |
+                                   aura::client::kResizeBehaviorCanMaximize |
                                    aura::client::kResizeBehaviorCanMinimize |
                                    aura::client::kResizeBehaviorCanResize);
   return *this;
diff --git a/ash/test/time_of_day_test_util.cc b/ash/test/time_of_day_test_util.cc
new file mode 100644
index 0000000..1b11323
--- /dev/null
+++ b/ash/test/time_of_day_test_util.cc
@@ -0,0 +1,29 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/test/time_of_day_test_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+
+namespace {
+
+// `ASSERT_TRUE()` requires a function signature that returns `void`.
+void ToTimeTodayInternal(const TimeOfDay& time_of_day,
+                         base::Time* time_today_out) {
+  const absl::optional<base::Time> time_today = time_of_day.ToTimeToday();
+  ASSERT_TRUE(time_today);
+  *time_today_out = *time_today;
+}
+
+}  // namespace
+
+base::Time ToTimeToday(const TimeOfDay& time_of_day) {
+  base::Time time_today;
+  ToTimeTodayInternal(time_of_day, &time_today);
+  return time_today;
+}
+
+}  // namespace ash
diff --git a/ash/test/time_of_day_test_util.h b/ash/test/time_of_day_test_util.h
new file mode 100644
index 0000000..76b13c7
--- /dev/null
+++ b/ash/test/time_of_day_test_util.h
@@ -0,0 +1,20 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_TEST_TIME_OF_DAY_TEST_UTIL_H_
+#define ASH_TEST_TIME_OF_DAY_TEST_UTIL_H_
+
+#include "ash/system/time/time_of_day.h"
+#include "base/time/time.h"
+
+namespace ash {
+
+// Same as `TimeOfDay::ToTimeToday()` except triggers a gtest assertion failure
+// if the conversion fails. This behavior is only acceptable in tests; failures
+// must be handled gracefully in the field.
+base::Time ToTimeToday(const TimeOfDay& time_of_day);
+
+}  // namespace ash
+
+#endif  // ASH_TEST_TIME_OF_DAY_TEST_UTIL_H_
diff --git a/ash/webui/help_app_ui/help_app_manager_factory.cc b/ash/webui/help_app_ui/help_app_manager_factory.cc
index 58bd8fc..ff2e830 100644
--- a/ash/webui/help_app_ui/help_app_manager_factory.cc
+++ b/ash/webui/help_app_ui/help_app_manager_factory.cc
@@ -39,9 +39,10 @@
   return context;
 }
 
-KeyedService* HelpAppManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+HelpAppManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new HelpAppManager(
+  return std::make_unique<HelpAppManager>(
       local_search_service::LocalSearchServiceProxyFactory::
           GetForBrowserContext(context));
 }
diff --git a/ash/webui/help_app_ui/help_app_manager_factory.h b/ash/webui/help_app_ui/help_app_manager_factory.h
index 71ebe259..bcd477cc 100644
--- a/ash/webui/help_app_ui/help_app_manager_factory.h
+++ b/ash/webui/help_app_ui/help_app_manager_factory.h
@@ -30,7 +30,7 @@
   // BrowserContextKeyedServiceFactory:
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsNULLWhileTesting() const override;
 };
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 7446719..ec16ea9e 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -234,7 +234,8 @@
     // Create non maximizable window so that it's centered when created,
     // then allow maximize/fullscreen state.
     window->SetProperty(aura::client::kResizeBehaviorKey,
-                        aura::client::kResizeBehaviorCanMaximize |
+                        aura::client::kResizeBehaviorCanFullscreen |
+                            aura::client::kResizeBehaviorCanMaximize |
                             aura::client::kResizeBehaviorCanMinimize |
                             aura::client::kResizeBehaviorCanResize);
     return window;
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
index f2e0436..b588a90b 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -171,7 +171,8 @@
     }
     aura::Window* window = aura::test::CreateTestWindowWithDelegateAndType(
         delegate, params.type, 0, params.bounds, NULL, params.show_on_creation);
-    int32_t behavior = aura::client::kResizeBehaviorNone;
+    int32_t behavior = aura::client::kResizeBehaviorNone |
+                       aura::client::kResizeBehaviorCanFullscreen;
     behavior |= params.can_resize ? aura::client::kResizeBehaviorCanResize : 0;
     behavior |=
         params.can_maximize ? aura::client::kResizeBehaviorCanMaximize : 0;
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 2ac6e79..1db0ea17 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -394,6 +394,11 @@
   return window_util::IsWindowUserPositionable(window_);
 }
 
+bool WindowState::CanFullscreen() const {
+  return (window_->GetProperty(aura::client::kResizeBehaviorKey) &
+          aura::client::kResizeBehaviorCanFullscreen) != 0;
+}
+
 bool WindowState::CanMaximize() const {
   return (window_->GetProperty(aura::client::kResizeBehaviorKey) &
           aura::client::kResizeBehaviorCanMaximize) != 0;
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index dead5bb83..e751824 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -284,6 +284,7 @@
   bool IsUserPositionable() const;
 
   // Checks if the window can change its state accordingly.
+  bool CanFullscreen() const;
   bool CanMaximize() const;
   bool CanMinimize() const;
   bool CanResize() const;
diff --git a/ash/wm/window_state_unittest.cc b/ash/wm/window_state_unittest.cc
index e8a5a29..2679db7 100644
--- a/ash/wm/window_state_unittest.cc
+++ b/ash/wm/window_state_unittest.cc
@@ -1271,6 +1271,33 @@
   EXPECT_TRUE(displays[0].bounds().Contains(window->bounds()));
 }
 
+TEST_F(WindowStateTest, CanFullscreen) {
+  std::unique_ptr<aura::Window> window(
+      CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
+  WindowState* window_state = WindowState::Get(window.get());
+
+  int behaviour = window->GetProperty(aura::client::kResizeBehaviorKey);
+
+  window->SetProperty(aura::client::kResizeBehaviorKey,
+                      behaviour | aura::client::kResizeBehaviorCanFullscreen);
+  EXPECT_TRUE(window_state->CanFullscreen());
+  ToggleFullScreen(window_state, nullptr);
+  EXPECT_TRUE(window_state->IsFullscreen());
+  ToggleFullScreen(window_state, nullptr);
+  EXPECT_FALSE(window_state->IsFullscreen());
+
+  // TODO(ffred): remove this once we separate can maximize and can fullscreen
+  // concepts.
+  window->SetProperty(
+      aura::client::kResizeBehaviorKey,
+      behaviour & ~(aura::client::kResizeBehaviorCanMaximize |
+                    aura::client::kResizeBehaviorCanFullscreen));
+  EXPECT_FALSE(window_state->CanFullscreen());
+  EXPECT_FALSE(window_state->CanMaximize());
+  ToggleFullScreen(window_state, nullptr);
+  EXPECT_FALSE(window_state->IsFullscreen());
+}
+
 TEST_F(WindowStateTest, CanConsumeSystemKeys) {
   std::unique_ptr<aura::Window> window(
       CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
diff --git a/ash/wm/window_state_util.cc b/ash/wm/window_state_util.cc
index 1ea54de9..dac3beb8 100644
--- a/ash/wm/window_state_util.cc
+++ b/ash/wm/window_state_util.cc
@@ -16,7 +16,8 @@
   // Window which cannot be maximized should not be full screen'ed.
   // It can, however, be restored if it was full screen'ed.
   bool is_fullscreen = window_state->IsFullscreen();
-  if (!is_fullscreen && !window_state->CanMaximize()) {
+  if (!is_fullscreen &&
+      !(window_state->CanMaximize() || window_state->CanFullscreen())) {
     // If `window` cannot be maximized, then do a window bounce animation.
     wm::AnimateWindow(window_state->window(), wm::WINDOW_ANIMATION_TYPE_BOUNCE);
     return;
diff --git a/base/allocator/partition_allocator/partition_alloc_base/logging.cc b/base/allocator/partition_allocator/partition_alloc_base/logging.cc
index a9640b3..1d68eba 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/logging.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/logging.cc
@@ -16,6 +16,7 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/alias.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/strings/safe_sprintf.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/strings/string_util.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/strings/stringprintf.h"
 #include "build/build_config.h"
@@ -39,10 +40,6 @@
 #include <unistd.h>
 #endif
 
-#include <cstring>
-#include <ostream>
-#include <string>
-
 #include "base/allocator/partition_allocator/partition_alloc_base/posix/eintr_wrapper.h"
 
 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
@@ -155,7 +152,7 @@
 
 LogMessage::~LogMessage() {
   stream_ << '\n';
-  std::string str_newline(stream_.c_str());
+  const char* str_newline = stream_.c_str();
 
   // Give any log message handler first dibs on the message.
   if (g_log_message_handler &&
@@ -166,7 +163,7 @@
   }
 
   // Always use RawLog() if g_log_message_handler doesn't filter messages.
-  RawLog(severity_, str_newline.c_str());
+  RawLog(severity_, str_newline);
 }
 
 // writes the common header info to the stream
@@ -204,8 +201,9 @@
 #endif
 }
 
-PA_COMPONENT_EXPORT(PARTITION_ALLOC)
-std::string SystemErrorCodeToString(SystemErrorCode error_code) {
+void SystemErrorCodeToStream(base::strings::CStringBuilder& os,
+                             SystemErrorCode error_code) {
+  char buffer[256];
 #if BUILDFLAG(IS_WIN)
   const int kErrorMessageBufferSize = 256;
   char msgbuf[kErrorMessageBufferSize];
@@ -215,16 +213,21 @@
   if (len) {
     // Messages returned by system end with line breaks.
     const char* whitespace_pos = base::strings::FindLastNotOf(msgbuf, "\n\r ");
-    const char* message = whitespace_pos ? whitespace_pos + 1 : msgbuf;
-    return std::string(message) +
-           base::TruncatingStringPrintf(" (0x%lX)", error_code);
+    if (whitespace_pos) {
+      size_t whitespace_index = whitespace_pos - msgbuf + 1;
+      msgbuf[whitespace_index] = '\0';
+    }
+    base::strings::SafeSPrintf(buffer, "%s (0x%x)", msgbuf, error_code);
+    os << buffer;
+    return;
   }
-  return base::TruncatingStringPrintf(
-      "Error (0x%lX) while retrieving error. (0x%lX)", GetLastError(),
-      error_code);
+  base::strings::SafeSPrintf(buffer,
+                             "Error (0x%x) while retrieving error. (0x%x)",
+                             GetLastError(), error_code);
+  os << buffer;
 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
-  return base::safe_strerror(error_code) +
-         base::TruncatingStringPrintf(" (%d)", error_code);
+  base::safe_strerror_r(error_code, buffer, sizeof(buffer));
+  os << buffer << " (" << error_code << ")";
 #endif  // BUILDFLAG(IS_WIN)
 }
 
@@ -236,7 +239,8 @@
     : LogMessage(file, line, severity), err_(err) {}
 
 Win32ErrorLogMessage::~Win32ErrorLogMessage() {
-  stream() << ": " << SystemErrorCodeToString(err_).c_str();
+  stream() << ": ";
+  SystemErrorCodeToStream(stream(), err_);
   // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
   // field) and use Alias in hopes that it makes it into crash dumps.
   DWORD last_error = err_;
@@ -250,7 +254,8 @@
     : LogMessage(file, line, severity), err_(err) {}
 
 ErrnoLogMessage::~ErrnoLogMessage() {
-  stream() << ": " << SystemErrorCodeToString(err_).c_str();
+  stream() << ": ";
+  SystemErrorCodeToStream(stream(), err_);
   // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
   // field) and use Alias in hopes that it makes it into crash dumps.
   int last_error = err_;
diff --git a/base/allocator/partition_allocator/partition_alloc_base/logging.h b/base/allocator/partition_allocator/partition_alloc_base/logging.h
index c618e1b..0d00627 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/logging.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/logging.h
@@ -161,7 +161,7 @@
                                           const char* file,
                                           int line,
                                           size_t message_start,
-                                          const std::string& str);
+                                          const char* str);
 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
 void SetLogMessageHandler(LogMessageHandlerFunction handler);
 PA_COMPONENT_EXPORT(PARTITION_ALLOC)
diff --git a/build/config/arm.gni b/build/config/arm.gni
index cc82ed5..5b404c1 100644
--- a/build/config/arm.gni
+++ b/build/config/arm.gni
@@ -41,6 +41,8 @@
 
   # For lacros build, we use ARM v8 by default.
   if (is_chromeos_lacros && arm_arch == "") {
+    # TODO(crbug.com/1467681) Enable i8mm and dotprod instructions for ffmpeg
+    # if ever we update to a version of arm that supports these instructions.
     arm_version = 8
     arm_arch = "armv8-a+crc"
   }
diff --git a/buildtools/reclient_cfgs/configure_reclient_cfgs.py b/buildtools/reclient_cfgs/configure_reclient_cfgs.py
index 96b81b3..807c60ce 100755
--- a/buildtools/reclient_cfgs/configure_reclient_cfgs.py
+++ b/buildtools/reclient_cfgs/configure_reclient_cfgs.py
@@ -35,7 +35,11 @@
 
 def NaclRevision():
     nacl_dir = os.path.join(CHROMIUM_SRC, 'native_client')
-    if not os.path.exists(nacl_dir):
+    # With git submodules, nacl_dir will always exist, regardless if it is
+    # cloned or not. To detect if nacl is actually cloned, check content of the
+    # repository. We assume that if README.md exists, then the repository is
+    # cloned.
+    if not os.path.exists(os.path.join(nacl_dir, 'README.md')):
       return None
     return subprocess.check_output(
         ['git', 'log', '-1', '--format=%H'],
diff --git a/chrome/VERSION b/chrome/VERSION
index d631ded..e8ffcd7 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=118
 MINOR=0
-BUILD=5965
+BUILD=5966
 PATCH=0
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index b84d828..7f100f55 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -1790,19 +1790,19 @@
     No preloading
   </message>
   <message name="IDS_SETTINGS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY" desc="Short explanation of what the no preloading mode does in the Preload Pages setting.">
-    Pages load only after you open them.
+    Pages load only after you open them
   </message>
   <message name="IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_TITLE" desc="Name of the standard preloading option for the Preload Pages settings page. This option enables preloading pages that Chrome believes the user is likely to navigate to.">
     Standard preloading
   </message>
   <message name="IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_SUMMARY" desc="Short explanation of what the standard preloading mode does in the Preload Pages setting.">
-    Some of the pages you visit are preloaded.
+    Some of the pages you visit are preloaded
   </message>
   <message name="IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_ONE" desc="First bullet point in the standard preloading and when on column. Informs the user about what the standard preloading setting does.">
-    Browsing and searching is faster.
+    Browsing and searching is faster
   </message>
   <message name="IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_TWO" desc="Second bullet point in the standard preloading and when on column. Informs the user about what the standard preloading setting does.">
-    Chrome preloads pages you're likely to visit, so that they load more quickly when you visit them.
+    Chrome preloads pages you're likely to visit, so that they load more quickly when you visit them
   </message>
   <message name="IDS_SETTINGS_PRELOAD_PAGES_EXTENDED_PRELOADING_TITLE" desc="Name of the extended preloading option for the Preload Pages settings page. This option enables more extensive preloading of pages that Chrome believes the user is likely to navigate to.">
     Extended preloading
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY.png.sha1
index 1b58ef6e0..a66e5c1 100644
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY.png.sha1
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY.png.sha1
@@ -1 +1 @@
-6c9be8d814a22a338de2daecd6302de60ced4cbe
\ No newline at end of file
+757fcd1b878a69019c4299e787a83590ad1aeed6
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_SUMMARY.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_SUMMARY.png.sha1
index 72ed35c..a66e5c1 100644
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_SUMMARY.png.sha1
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_SUMMARY.png.sha1
@@ -1 +1 @@
-fd2d0eb86ab1e99b0d856b2c8e144594cfe1fdc5
\ No newline at end of file
+757fcd1b878a69019c4299e787a83590ad1aeed6
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_ONE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_ONE.png.sha1
index 7cccdab..a66e5c1 100644
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_ONE.png.sha1
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_ONE.png.sha1
@@ -1 +1 @@
-3dbd409914242f18392fb50a5bf6f2878c34f8c9
\ No newline at end of file
+757fcd1b878a69019c4299e787a83590ad1aeed6
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_TWO.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_TWO.png.sha1
index 3ee35cb..a66e5c1 100644
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_TWO.png.sha1
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PRELOAD_PAGES_STANDARD_PRELOADING_WHEN_ON_BULLET_TWO.png.sha1
@@ -1 +1 @@
-3f64a15797c82e4faf2860330e3dd48f50779907
\ No newline at end of file
+757fcd1b878a69019c4299e787a83590ad1aeed6
\ No newline at end of file
diff --git a/chrome/browser/ash/arc/idle_manager/arc_idle_manager.cc b/chrome/browser/ash/arc/idle_manager/arc_idle_manager.cc
index 048279c..b3a3a308 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_idle_manager.cc
+++ b/chrome/browser/ash/arc/idle_manager/arc_idle_manager.cc
@@ -7,7 +7,6 @@
 #include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "ash/components/arc/arc_features.h"
 #include "ash/components/arc/mojom/power.mojom.h"
-#include "ash/components/arc/power/arc_power_bridge.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
@@ -52,7 +51,7 @@
  private:
   friend class base::NoDestructor<ArcIdleManagerFactory>;
 
-  ArcIdleManagerFactory() = default;
+  ArcIdleManagerFactory() { DependsOn(ArcPowerBridgeFactory::GetInstance()); }
   ~ArcIdleManagerFactory() override = default;
 };
 
@@ -88,8 +87,10 @@
   auto* const power_bridge = ArcPowerBridge::GetForBrowserContext(context);
 
   // This maybe null in unit tests.
-  if (power_bridge)
+  if (power_bridge) {
     power_bridge->DisableAndroidIdleControl();
+    powerbridge_observation_.Observe(power_bridge);
+  }
 
   DCHECK(bridge_);
   bridge_->power()->AddObserver(this);
@@ -109,6 +110,9 @@
   // After this is done, we will no longer get connection notifications.
   bridge_->power()->RemoveObserver(this);
 
+  // No more notifications about VM resumed.
+  powerbridge_observation_.Reset();
+
   // Safeguard against resource leak by observers.
   OnConnectionClosed();
 }
@@ -154,6 +158,21 @@
   delegate_->SetInteractiveMode(bridge_, !should_throttle);
 }
 
+void ArcIdleManager::OnVmResumed() {
+  if (!should_throttle()) {
+    // A resume happens because there was a prior suspend.
+    // That earlier suspend counts as first-idle.
+    first_idle_happened_ = true;
+
+    ThrottleInstance(false);
+  }
+}
+
+void ArcIdleManager::OnWillDestroyArcPowerBridge() {
+  // No more notifications about VM resumed.
+  powerbridge_observation_.Reset();
+}
+
 void ArcIdleManager::LogScreenOffTimer(bool toggle_timer) {
   if (toggle_timer) {
     // Start measuring now.
diff --git a/chrome/browser/ash/arc/idle_manager/arc_idle_manager.h b/chrome/browser/ash/arc/idle_manager/arc_idle_manager.h
index 6ea2a72..f8235e5 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_idle_manager.h
+++ b/chrome/browser/ash/arc/idle_manager/arc_idle_manager.h
@@ -9,8 +9,10 @@
 #include <string>
 
 #include "ash/components/arc/mojom/power.mojom.h"
+#include "ash/components/arc/power/arc_power_bridge.h"
 #include "ash/components/arc/session/connection_observer.h"
 #include "base/memory/raw_ptr.h"
+#include "base/scoped_observation.h"
 #include "base/sequence_checker.h"
 #include "base/timer/elapsed_timer.h"
 #include "chrome/browser/ash/throttle_service.h"
@@ -22,6 +24,7 @@
 // This class holds a number of observers which watch for all conditions that
 // gate the triggering of ARC's Idle (Doze) mode.
 class ArcIdleManager : public KeyedService,
+                       public ArcPowerBridge::Observer,
                        public ash::ThrottleService,
                        public ConnectionObserver<mojom::PowerInstance> {
  public:
@@ -63,6 +66,10 @@
   void OnConnectionReady() override;
   void OnConnectionClosed() override;
 
+  // ArcPowerBridge::Observer
+  void OnVmResumed() override;
+  void OnWillDestroyArcPowerBridge() override;
+
   // Replaces the delegate so we can monitor switches without touching actual
   // power state, for unit test purposes.
   void set_delegate_for_testing(std::unique_ptr<Delegate> delegate) {
@@ -85,6 +92,9 @@
   const raw_ptr<ArcBridgeService, ExperimentalAsh> bridge_;
 
   base::ElapsedTimer interactive_off_span_timer_;
+
+  base::ScopedObservation<ArcPowerBridge, ArcPowerBridge::Observer>
+      powerbridge_observation_{this};
 };
 
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/idle_manager/arc_idle_manager_unittest.cc b/chrome/browser/ash/arc/idle_manager/arc_idle_manager_unittest.cc
index 0c76f3f5..82230658 100644
--- a/chrome/browser/ash/arc/idle_manager/arc_idle_manager_unittest.cc
+++ b/chrome/browser/ash/arc/idle_manager/arc_idle_manager_unittest.cc
@@ -190,9 +190,13 @@
 };
 
 // Tests that ArcIdleManager can be constructed and destructed.
-
 TEST_F(ArcIdleManagerTest, TestConstructDestruct) {}
 
+// Tests that powerbridge early death causes no DCHECKs in observer list.
+TEST_F(ArcIdleManagerTest, TestEarlyPowerBridgeDeath) {
+  arc_idle_manager()->OnWillDestroyArcPowerBridge();
+}
+
 // Tests that ArcIdleManager responds appropriately to various observers.
 TEST_F(ArcIdleManagerTest, TestThrottleInstance) {
   // When no one blocks, it should enable idle;
@@ -250,9 +254,19 @@
   EXPECT_EQ(5U, interactive_enabled_counter());
   EXPECT_EQ(6U, interactive_disabled_counter());
 
+  // ResumeVm event when not idle causes additional idle-disable event.
+  arc_idle_manager()->OnVmResumed();
+  EXPECT_EQ(6U, interactive_enabled_counter());
+  EXPECT_EQ(6U, interactive_disabled_counter());
+
   // Reset.
   arc_window_observer()->SetActive(false);
-  EXPECT_EQ(5U, interactive_enabled_counter());
+  EXPECT_EQ(6U, interactive_enabled_counter());
+  EXPECT_EQ(7U, interactive_disabled_counter());
+
+  // ResumeVm event when idle does not generate switch events.
+  arc_idle_manager()->OnVmResumed();
+  EXPECT_EQ(6U, interactive_enabled_counter());
   EXPECT_EQ(7U, interactive_disabled_counter());
 }
 
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.cc b/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.cc
index 5dcda2b9..b52eba7 100644
--- a/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.cc
+++ b/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.cc
@@ -35,17 +35,14 @@
   auto* const power_bridge = ArcPowerBridge::GetForBrowserContext(context);
   // Could be nullptr in unit tests.
   if (power_bridge)
-    power_bridge->AddObserver(this);
+    powerbridge_observation_.Observe(power_bridge);
 }
 
 void ArcPowerThrottleObserver::StopObserving() {
   // Make sure |timer_| is not fired after stopping observing.
   timer_.Stop();
 
-  auto* const power_bridge = ArcPowerBridge::GetForBrowserContext(context());
-  // Could be nullptr in unit tests.
-  if (power_bridge)
-    power_bridge->RemoveObserver(this);
+  powerbridge_observation_.Reset();
 
   ThrottleObserver::StopObserving();
 }
@@ -85,4 +82,9 @@
   }
 }
 
+void ArcPowerThrottleObserver::OnWillDestroyArcPowerBridge() {
+  // No more notifications about VM resumed.
+  powerbridge_observation_.Reset();
+}
+
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.h b/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.h
index ac135ba..6476f39 100644
--- a/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.h
+++ b/chrome/browser/ash/arc/instance_throttle/arc_power_throttle_observer.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_ASH_ARC_INSTANCE_THROTTLE_ARC_POWER_THROTTLE_OBSERVER_H_
 
 #include "ash/components/arc/power/arc_power_bridge.h"
+#include "base/scoped_observation.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/ash/throttle_observer.h"
 
@@ -31,9 +32,13 @@
 
   // ArcPowerBridge::Observer:
   void OnPreAnr(mojom::AnrType type) override;
+  void OnWillDestroyArcPowerBridge() override;
 
  private:
   base::OneShotTimer timer_;
+
+  base::ScopedObservation<ArcPowerBridge, ArcPowerBridge::Observer>
+      powerbridge_observation_{this};
 };
 
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
index 11f7dfe..b1155a72 100644
--- a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
@@ -84,7 +84,7 @@
 constexpr float kAndroidFontScaleNormal = 1;
 
 // These values are based on
-// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/resources/ash/settings/os_a11y_page/captions_subpage.ts;l=142;drc=0918c7f73782a9575396f0c6b80a722b5a3d255a
+// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/resources/ash/settings/a11y_page/captions_subpage.ts;l=142;drc=0918c7f73782a9575396f0c6b80a722b5a3d255a
 constexpr char kTextShadowRaised[] = "-2px -2px 4px rgba(0, 0, 0, 0.5)";
 constexpr char kTextShadowDepressed[] = "2px 2px 4px rgba(0, 0, 0, 0.5)";
 constexpr char kTextShadowUniform[] =
diff --git a/chrome/browser/ash/arc/screen_capture/arc_screen_capture_session.cc b/chrome/browser/ash/arc/screen_capture/arc_screen_capture_session.cc
index 009df7e..a6dc15a 100644
--- a/chrome/browser/ash/arc/screen_capture/arc_screen_capture_session.cc
+++ b/chrome/browser/ash/arc/screen_capture/arc_screen_capture_session.cc
@@ -134,7 +134,8 @@
   scaler_ = gl_helper_->CreateScaler(
       gpu::GLHelper::ScalerQuality::SCALER_QUALITY_GOOD,
       gfx::Vector2d(desktop_size.width(), desktop_size.height()),
-      gfx::Vector2d(size_.width(), size_.height()), false, true, false);
+      gfx::Vector2d(size_.width(), size_.height()), /*flipped_source=*/true,
+      /*flip_output=*/true, /*swizzle=*/false);
 
   display_root_window_->GetHost()->compositor()->AddAnimationObserver(this);
 
diff --git a/chrome/browser/ash/crostini/ansible/ansible_management_service_factory.cc b/chrome/browser/ash/crostini/ansible/ansible_management_service_factory.cc
index 5850041..143f467 100644
--- a/chrome/browser/ash/crostini/ansible/ansible_management_service_factory.cc
+++ b/chrome/browser/ash/crostini/ansible/ansible_management_service_factory.cc
@@ -37,10 +37,11 @@
 AnsibleManagementServiceFactory::~AnsibleManagementServiceFactory() = default;
 
 // BrowserContextKeyedServiceFactory:
-KeyedService* AnsibleManagementServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+AnsibleManagementServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
-  return new AnsibleManagementService(profile);
+  return std::make_unique<AnsibleManagementService>(profile);
 }
 
 KeyedService* AnsibleManagementServiceFactory::SetTestingFactoryAndUse(
diff --git a/chrome/browser/ash/crostini/ansible/ansible_management_service_factory.h b/chrome/browser/ash/crostini/ansible/ansible_management_service_factory.h
index 3cedaeb..2fb0474c 100644
--- a/chrome/browser/ash/crostini/ansible/ansible_management_service_factory.h
+++ b/chrome/browser/ash/crostini/ansible/ansible_management_service_factory.h
@@ -34,7 +34,7 @@
   ~AnsibleManagementServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/ash/drive/drive_integration_service.cc b/chrome/browser/ash/drive/drive_integration_service.cc
index 3a83120..d78a0f1d 100644
--- a/chrome/browser/ash/drive/drive_integration_service.cc
+++ b/chrome/browser/ash/drive/drive_integration_service.cc
@@ -106,10 +106,6 @@
 const base::FilePath::CharType kCacheFileDirectory[] =
     FILE_PATH_LITERAL("files");
 
-// Name of the directory used to store temporary files.
-const base::FilePath::CharType kTemporaryFileDirectory[] =
-    FILE_PATH_LITERAL("tmp");
-
 void DeleteDirectoryContents(const base::FilePath& dir) {
   base::FileEnumerator content_enumerator(
       dir, false,
@@ -141,51 +137,55 @@
 // Must be run on the same task runner used by |cache| and |resource_metadata|.
 FileError InitializeMetadata(
     const base::FilePath& cache_root_directory,
-    internal::ResourceMetadataStorage* metadata_storage,
+    internal::ResourceMetadataStorage* const metadata_storage,
     const base::FilePath& downloads_directory) {
-  if (!base::DirectoryExists(
-          cache_root_directory.Append(kTemporaryFileDirectory))) {
-    if (base::SysInfo::IsRunningOnChromeOS()) {
-      LOG(ERROR) << "/tmp should have been created as clear.";
-    }
-    // Create /tmp directory as encrypted. Cryptohome will re-create /tmp
-    // direcotry at the next login.
-    if (!base::CreateDirectory(
-            cache_root_directory.Append(kTemporaryFileDirectory))) {
-      LOG(WARNING) << "Failed to create directories.";
+  const base::FilePath tmp_dir = cache_root_directory.Append("tmp");
+  const base::FilePath metadata_dir =
+      cache_root_directory.Append(kMetadataDirectory);
+  const base::FilePath cache_file_dir =
+      cache_root_directory.Append(kCacheFileDirectory);
+
+  // Create tmp directory as encrypted. Cryptohome will re-create tmp directory
+  // at the next login.
+  for (const base::FilePath& dir : {tmp_dir, metadata_dir, cache_file_dir}) {
+    if (!base::CreateDirectory(dir)) {
+      PLOG(ERROR) << "Cannot create dir " << dir;
       return FILE_ERROR_FAILED;
     }
   }
-  // Files in temporary directory need not persist across sessions. Clean up
-  // the directory content while initialization. The directory itself should not
-  // be deleted because it's created by cryptohome in clear and shouldn't be
+
+  // Files in tmp directory need not persist across sessions. Clean up the
+  // directory content while initialization. The directory itself should not be
+  // deleted because it's created by cryptohome in clear and shouldn't be
   // re-created as encrypted.
-  DeleteDirectoryContents(cache_root_directory.Append(kTemporaryFileDirectory));
-  if (!base::CreateDirectory(cache_root_directory.Append(kMetadataDirectory)) ||
-      !base::CreateDirectory(
-          cache_root_directory.Append(kCacheFileDirectory))) {
-    LOG(WARNING) << "Failed to create directories.";
-    return FILE_ERROR_FAILED;
-  }
+  DeleteDirectoryContents(tmp_dir);
 
   // Change permissions of cache file directory to u+rwx,og+x (711) in order to
   // allow archive files in that directory to be mounted by cros-disks.
-  base::SetPosixFilePermissions(
-      cache_root_directory.Append(kCacheFileDirectory),
-      base::FILE_PERMISSION_USER_MASK | base::FILE_PERMISSION_EXECUTE_BY_GROUP |
-          base::FILE_PERMISSION_EXECUTE_BY_OTHERS);
+  if (!base::SetPosixFilePermissions(
+          cache_file_dir, base::FILE_PERMISSION_USER_MASK |
+                              base::FILE_PERMISSION_EXECUTE_BY_GROUP |
+                              base::FILE_PERMISSION_EXECUTE_BY_OTHERS)) {
+    PLOG(ERROR) << "Cannot set permissions on dir " << cache_file_dir;
+  }
 
   // If attempting to migrate to DriveFS without previous Drive sync data
   // present, skip the migration.
-  if (base::IsDirectoryEmpty(cache_root_directory.Append(kMetadataDirectory))) {
+  if (base::IsDirectoryEmpty(metadata_dir)) {
+    VLOG(1) << "Dir " << metadata_dir << " is empty";
     return FILE_ERROR_FAILED;
   }
 
-  internal::ResourceMetadataStorage::UpgradeOldDB(
-      metadata_storage->directory_path());
+  DCHECK(metadata_storage);
+  if (!internal::ResourceMetadataStorage::UpgradeOldDB(
+          metadata_storage->directory_path())) {
+    LOG(ERROR) << "Cannot upgrade the metadata storage "
+               << metadata_storage->directory_path();
+  }
 
   if (!metadata_storage->Initialize()) {
-    LOG(WARNING) << "Failed to initialize the metadata storage.";
+    LOG(ERROR) << "Cannot initialize the metadata storage "
+               << metadata_storage->directory_path();
     return FILE_ERROR_FAILED;
   }
 
diff --git a/chrome/browser/ash/drive/drive_integration_service_unittest.cc b/chrome/browser/ash/drive/drive_integration_service_unittest.cc
index 433c00a..068f833b 100644
--- a/chrome/browser/ash/drive/drive_integration_service_unittest.cc
+++ b/chrome/browser/ash/drive/drive_integration_service_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "content/public/test/browser_task_environment.h"
-#include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace drive {
diff --git a/chrome/browser/ash/file_manager/file_manager_jstest.cc b/chrome/browser/ash/file_manager/file_manager_jstest.cc
index 39bd9ee..fca9ef3 100644
--- a/chrome/browser/ash/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_jstest.cc
@@ -332,11 +332,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ReducerAndroidApps) {
-  RunTestURL("state/reducers/android_apps_unittest.js");
+  RunTestURL("state/ducks/android_apps_unittest.js");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ReducerFolderShortcuts) {
-  RunTestURL("state/reducers/folder_shortcuts_unittest.js");
+  RunTestURL("state/ducks/folder_shortcuts_unittest.js");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ReducerCurrentDirectory) {
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc
index fcc3076..c12d877c 100644
--- a/chrome/browser/ash/file_manager/file_tasks.cc
+++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -81,6 +81,7 @@
 #include "components/services/app_service/public/cpp/app_update.h"
 #include "components/services/app_service/public/cpp/file_handler.h"
 #include "components/services/app_service/public/cpp/file_handler_info.h"
+#include "components/services/app_service/public/cpp/types_util.h"
 #include "content/public/browser/network_service_instance.h"
 #include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/entry_info.h"
@@ -1067,8 +1068,7 @@
     gfx::NativeWindow modal_parent,
     ash::office_fallback::FallbackReason fallback_reason) {
   // If QuickOffice is not installed, don't launch dialog.
-  if (!IsExtensionInstalled(profile,
-                            extension_misc::kQuickOfficeComponentExtensionId)) {
+  if (!IsQuickOfficeInstalled(profile)) {
     LOG(ERROR) << "Cannot fallback to QuickOffice when it is not installed";
     return false;
   }
@@ -1267,11 +1267,21 @@
   return IsFilesAppId(task.app_id) && action_id == kActionIdOpenInOffice;
 }
 
-bool IsExtensionInstalled(Profile* profile, const std::string& extension_id) {
-  extensions::ExtensionRegistry* registry =
-      extensions::ExtensionRegistry::Get(profile);
-  return registry->GetExtensionById(extension_id,
-                                    extensions::ExtensionRegistry::ENABLED);
+bool IsQuickOfficeInstalled(Profile* profile) {
+  apps::AppServiceProxy* proxy =
+      apps::AppServiceProxyFactory::GetForProfile(profile);
+  if (!proxy) {
+    return false;
+  }
+  // The AppRegistryCache will contain the QuickOffice extension whether on Ash
+  // or Lacros.
+  bool installed = false;
+  proxy->AppRegistryCache().ForOneApp(
+      extension_misc::kQuickOfficeComponentExtensionId,
+      [&installed](const apps::AppUpdate& update) {
+        installed = apps_util::IsInstalled(update.Readiness());
+      });
+  return installed;
 }
 
 bool IsHtmlFile(const base::FilePath& path) {
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h
index 150be95..e44732e4 100644
--- a/chrome/browser/ash/file_manager/file_tasks.h
+++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -449,7 +449,7 @@
 
 bool IsOpenInOfficeTask(const TaskDescriptor& task);
 
-bool IsExtensionInstalled(Profile* profile, const std::string& extension_id);
+bool IsQuickOfficeInstalled(Profile* profile);
 
 // Returns whether |path| is an HTML file according to its extension.
 bool IsHtmlFile(const base::FilePath& path);
diff --git a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
index bdb562b..0323d84 100644
--- a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
@@ -70,6 +70,7 @@
 #include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "components/drive/file_errors.h"
+#include "components/services/app_service/public/cpp/app_types.h"
 #include "components/services/app_service/public/cpp/intent_util.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/test/browser_test.h"
@@ -78,6 +79,7 @@
 #include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/entry_info.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/common/constants.h"
 #include "net/base/mime_util.h"
 #include "services/network/test/test_network_connection_tracker.h"
 #include "storage/browser/file_system/external_mount_points.h"
@@ -620,45 +622,6 @@
   ASSERT_EQ("\"Received tiffAction with: test_small.tiff\"", message);
 }
 
-IN_PROC_BROWSER_TEST_P(FileTasksBrowserTest, IsExtensionInstalled) {
-  // TODO(b/287165243): Fix the test and remove this.
-  if (GetParam().crosapi_state == TestProfileParam::CrosapiParam::kEnabled) {
-    GTEST_SKIP()
-        << "Skipping test body for CrosapiParam::kEnabled, see b/287165243.";
-  }
-
-  if (profile_type() == TestProfileType::kGuest) {
-    // The extension can't install in guest mode.
-    return;
-  }
-  Profile* const profile = browser()->profile();
-  // Install new extension.
-  auto extension = InstallTiffHandlerChromeApp(profile);
-  ASSERT_TRUE(IsExtensionInstalled(profile, extension->id()));
-
-  extensions::ExtensionRegistry* registry =
-      extensions::ExtensionRegistry::Get(profile);
-  // Uninstall extension.
-  registry->RemoveEnabled(extension->id());
-  ASSERT_FALSE(IsExtensionInstalled(profile, extension->id()));
-}
-
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-// This test only runs with the is_chrome_branded GN flag set because otherwise
-// QuickOffice is not installed.
-IN_PROC_BROWSER_TEST_P(FileTasksBrowserTest, IsExtensionInstalledQuickOffice) {
-  // TODO(b/287165243): Fix the test and remove this.
-  if (GetParam().crosapi_state == TestProfileParam::CrosapiParam::kEnabled) {
-    GTEST_SKIP()
-        << "Skipping test body for CrosapiParam::kEnabled, see b/287165243.";
-  }
-
-  Profile* const profile = browser()->profile();
-  ASSERT_TRUE(IsExtensionInstalled(
-      profile, extension_misc::kQuickOfficeComponentExtensionId));
-}
-#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
-
 const TaskDescriptor CreateWebDriveOfficeTask() {
   // The SWA actionId is prefixed with chrome://file-manager/?ACTION_ID.
   const std::string& full_action_id =
@@ -684,9 +647,33 @@
       file);
 }
 
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-// This test only runs with the is_chrome_branded GN flag set because otherwise
+// These tests only run with the is_chrome_branded GN flag set because otherwise
 // QuickOffice is not installed.
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+// Test that the Fallback dialog can be shown when Quick Office is installed.
+IN_PROC_BROWSER_TEST_P(FileTasksBrowserTest, FallbackSucceedsWithQuickOffice) {
+  // TODO(b/287165243): Fix the test and remove this.
+  if (GetParam().crosapi_state == TestProfileParam::CrosapiParam::kEnabled) {
+    GTEST_SKIP()
+        << "Skipping test body for CrosapiParam::kEnabled, see b/287165243.";
+  }
+
+  if (profile_type() == TestProfileType::kIncognito) {
+    GTEST_SKIP()
+        << "There is no AppServiceProxy for incognito profiles as they are "
+           "ephemeral and have no apps persisted inside them.";
+  }
+
+  storage::FileSystemURL test_url;
+  Profile* const profile = browser()->profile();
+
+  // GetUserFallbackChoice() returns `True` because the Fallback dialog can be
+  // shown.
+  ASSERT_TRUE(GetUserFallbackChoice(
+      profile, CreateWebDriveOfficeTask(), {test_url}, nullptr,
+      ash::office_fallback::FallbackReason::kOffline));
+}
+
 IN_PROC_BROWSER_TEST_P(FileTasksBrowserTest, FallbackFailsNoQuickOffice) {
   // TODO(b/287165243): Fix the test and remove this.
   if (GetParam().crosapi_state == TestProfileParam::CrosapiParam::kEnabled) {
@@ -694,26 +681,27 @@
         << "Skipping test body for CrosapiParam::kEnabled, see b/287165243.";
   }
 
+  if (profile_type() == TestProfileType::kIncognito) {
+    GTEST_SKIP()
+        << "There is no AppServiceProxy, which is required to check "
+           "QuickOffice is installed, for incognito profiles as they are "
+           "ephemeral and have no apps persisted inside them.";
+  }
+
   storage::FileSystemURL test_url;
   Profile* const profile = browser()->profile();
-  extensions::ExtensionRegistry* registry =
-      extensions::ExtensionRegistry::Get(profile);
-  const extensions::Extension* quick_office = registry->GetInstalledExtension(
-      extension_misc::kQuickOfficeComponentExtensionId);
 
   // Uninstall QuickOffice.
-  registry->RemoveEnabled(extension_misc::kQuickOfficeComponentExtensionId);
+  extensions::ExtensionSystem::Get(profile)
+      ->extension_service()
+      ->RemoveComponentExtension(
+          extension_misc::kQuickOfficeComponentExtensionId);
+
   // GetUserFallbackChoice() returns `False` because QuickOffice is not
   // installed.
   ASSERT_FALSE(GetUserFallbackChoice(
       profile, CreateWebDriveOfficeTask(), {test_url}, nullptr,
       ash::office_fallback::FallbackReason::kOffline));
-  // Install QuickOffice.
-  registry->AddEnabled(quick_office);
-  // GetUserFallbackChoice() returns `True` because QuickOffice is installed.
-  ASSERT_TRUE(GetUserFallbackChoice(
-      profile, CreateWebDriveOfficeTask(), {test_url}, nullptr,
-      ash::office_fallback::FallbackReason::kOffline));
 }
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
diff --git a/chrome/browser/ash/guest_os/guest_os_mime_types_service_factory.cc b/chrome/browser/ash/guest_os/guest_os_mime_types_service_factory.cc
index 5d0b448..d9e31621 100644
--- a/chrome/browser/ash/guest_os/guest_os_mime_types_service_factory.cc
+++ b/chrome/browser/ash/guest_os/guest_os_mime_types_service_factory.cc
@@ -35,10 +35,11 @@
 
 GuestOsMimeTypesServiceFactory::~GuestOsMimeTypesServiceFactory() = default;
 
-KeyedService* GuestOsMimeTypesServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+GuestOsMimeTypesServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
-  return new GuestOsMimeTypesService(profile);
+  return std::make_unique<GuestOsMimeTypesService>(profile);
 }
 
 }  // namespace guest_os
diff --git a/chrome/browser/ash/guest_os/guest_os_mime_types_service_factory.h b/chrome/browser/ash/guest_os/guest_os_mime_types_service_factory.h
index 32f8f51c..735089d 100644
--- a/chrome/browser/ash/guest_os/guest_os_mime_types_service_factory.h
+++ b/chrome/browser/ash/guest_os/guest_os_mime_types_service_factory.h
@@ -30,7 +30,7 @@
   ~GuestOsMimeTypesServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/ash/guest_os/guest_os_registry_service_factory.cc b/chrome/browser/ash/guest_os/guest_os_registry_service_factory.cc
index 03a5ee41..3d1dc164 100644
--- a/chrome/browser/ash/guest_os/guest_os_registry_service_factory.cc
+++ b/chrome/browser/ash/guest_os/guest_os_registry_service_factory.cc
@@ -36,10 +36,11 @@
 
 GuestOsRegistryServiceFactory::~GuestOsRegistryServiceFactory() = default;
 
-KeyedService* GuestOsRegistryServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+GuestOsRegistryServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
-  return new GuestOsRegistryService(profile);
+  return std::make_unique<GuestOsRegistryService>(profile);
 }
 
 }  // namespace guest_os
diff --git a/chrome/browser/ash/guest_os/guest_os_registry_service_factory.h b/chrome/browser/ash/guest_os/guest_os_registry_service_factory.h
index 2a8a590..851cd56 100644
--- a/chrome/browser/ash/guest_os/guest_os_registry_service_factory.h
+++ b/chrome/browser/ash/guest_os/guest_os_registry_service_factory.h
@@ -30,7 +30,7 @@
   ~GuestOsRegistryServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/ash/guest_os/guest_os_share_path_factory.cc b/chrome/browser/ash/guest_os/guest_os_share_path_factory.cc
index 833d1d95..4d65d15a 100644
--- a/chrome/browser/ash/guest_os/guest_os_share_path_factory.cc
+++ b/chrome/browser/ash/guest_os/guest_os_share_path_factory.cc
@@ -37,10 +37,11 @@
 
 GuestOsSharePathFactory::~GuestOsSharePathFactory() = default;
 
-KeyedService* GuestOsSharePathFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+GuestOsSharePathFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
-  return new GuestOsSharePath(profile);
+  return std::make_unique<GuestOsSharePath>(profile);
 }
 
 }  // namespace guest_os
diff --git a/chrome/browser/ash/guest_os/guest_os_share_path_factory.h b/chrome/browser/ash/guest_os/guest_os_share_path_factory.h
index 285322a..f054381 100644
--- a/chrome/browser/ash/guest_os/guest_os_share_path_factory.h
+++ b/chrome/browser/ash/guest_os/guest_os_share_path_factory.h
@@ -29,7 +29,7 @@
   ~GuestOsSharePathFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/ash/net/DEPS b/chrome/browser/ash/net/DEPS
index 2a94e1b..77b9983 100644
--- a/chrome/browser/ash/net/DEPS
+++ b/chrome/browser/ash/net/DEPS
@@ -1,4 +1,10 @@
 specific_include_rules = {
+  "apn_migrator\.cc": [
+    "+ui/message_center/message_center.h",
+  ],
+  "apn_migrator_unittest\.cc": [
+    "+ui/message_center/message_center.h",
+  ],
   "system_proxy_manager_unittest\.cc": [
     "+services/network/network_context.h"
   ]
diff --git a/chrome/browser/ash/net/apn_migrator.cc b/chrome/browser/ash/net/apn_migrator.cc
index 4f41295..419275ee 100644
--- a/chrome/browser/ash/net/apn_migrator.cc
+++ b/chrome/browser/ash/net/apn_migrator.cc
@@ -6,8 +6,15 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/network_config_service.h"
+#include "ash/public/cpp/notification_utils.h"
+#include "ash/webui/settings/public/constants/routes.mojom.h"
 #include "base/containers/contains.h"
+#include "base/strings/escape.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chromeos/ash/components/login/login_state/login_state.h"
 #include "chromeos/ash/components/network/managed_cellular_pref_handler.h"
 #include "chromeos/ash/components/network/managed_network_configuration_handler.h"
@@ -18,6 +25,9 @@
 #include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
 #include "components/device_event_log/device_event_log.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/public/cpp/notification_types.h"
+#include "ui/message_center/public/cpp/notifier_id.h"
 
 namespace ash {
 
@@ -75,8 +85,51 @@
   return {ApnType::kDefault};
 }
 
+// Clicking on the notification will bring the user to the APN subpage.
+void ShowApnConfigurationDisabledNotification(
+    const std::string& access_point_name,
+    const std::string& guid) {
+  const std::string notification_id =
+      ApnMigrator::kShowApnConfigurationDisabledNotificationIdPrefix + guid;
+  auto on_click = base::BindRepeating(
+      [](const std::string& guid, const std::string& notification_id) {
+        message_center::MessageCenter::Get()->RemoveNotification(
+            notification_id, /*by_user=*/false);
+        const std::string apn_subpage =
+            ::chromeos::settings::mojom::kApnSubpagePath +
+            std::string("?guid=") +
+            base::EscapeUrlEncodedData(guid, /*use_plus=*/true);
+        chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
+            ProfileManager::GetActiveUserProfile(), apn_subpage);
+      },
+      guid, notification_id);
+
+  // TODO(b/162365553): Get final strings after string meeting.
+  std::unique_ptr<message_center::Notification> notification =
+      ash::CreateSystemNotificationPtr(
+          message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE,
+          notification_id,
+          u"Title for " + base::ASCIIToUTF16(access_point_name),
+          u"Message for " + base::ASCIIToUTF16(access_point_name),
+          /*display_source=*/std::u16string(), GURL(),
+          message_center::NotifierId(
+              message_center::NotifierType::SYSTEM_COMPONENT, notification_id,
+              ash::NotificationCatalogName::kMobileData),
+          message_center::RichNotificationData(),
+          new message_center::HandleNotificationClickDelegate(on_click),
+          kNotificationCellularAlertIcon,
+          message_center::SystemNotificationWarningLevel::WARNING);
+
+  message_center::MessageCenter::Get()->AddNotification(
+      std::move(notification));
+}
+
 }  // namespace
 
+// static
+const char ApnMigrator::kShowApnConfigurationDisabledNotificationIdPrefix[] =
+    "show_apn_configuration_disabled_notification_";
+
 ApnMigrator::ApnMigrator(
     ManagedCellularPrefHandler* managed_cellular_pref_handler,
     ManagedNetworkConfigurationHandler* network_configuration_handler,
@@ -371,8 +424,12 @@
         CellularNetworkMetricsLogger::LogUnmanagedCustomApnMigrationType(
             CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
                 kDoesNotMatchLastGoodApn);
-        // TODO(b/162365553): Surface a notification to the user indicating that
-        // their APN configuration was changed.
+
+        // Surfaces a notification that indicates that the Network's last good
+        // APN does not match the saved custom APN, and that the APN will be
+        // migrated in a disabled state to the new UI.
+        ShowApnConfigurationDisabledNotification(
+            pre_revamp_custom_apn->access_point_name, guid);
       }
       pre_revamp_custom_apn->apn_types =
           GetMigratedApnTypes(pre_revamp_custom_apn);
diff --git a/chrome/browser/ash/net/apn_migrator.h b/chrome/browser/ash/net/apn_migrator.h
index 34f9d6b..a5531db3 100644
--- a/chrome/browser/ash/net/apn_migrator.h
+++ b/chrome/browser/ash/net/apn_migrator.h
@@ -26,6 +26,9 @@
 class COMPONENT_EXPORT(CHROMEOS_NETWORK) ApnMigrator
     : public NetworkStateHandlerObserver {
  public:
+  // Notification ID prefix prepended to the cellular network GUID.
+  static const char kShowApnConfigurationDisabledNotificationIdPrefix[];
+
   ApnMigrator(
       ManagedCellularPrefHandler* managed_cellular_pref_handler,
       ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
diff --git a/chrome/browser/ash/net/apn_migrator_unittest.cc b/chrome/browser/ash/net/apn_migrator_unittest.cc
index f4edd35..fe249154 100644
--- a/chrome/browser/ash/net/apn_migrator_unittest.cc
+++ b/chrome/browser/ash/net/apn_migrator_unittest.cc
@@ -5,12 +5,16 @@
 #include "chrome/browser/ash/net/apn_migrator.h"
 
 #include "ash/constants/ash_features.h"
+#include "ash/test/ash_test_base.h"
 #include "base/check_op.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
+#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/ash/components/login/login_state/login_state.h"
 #include "chromeos/ash/components/network/device_state.h"
 #include "chromeos/ash/components/network/fake_stub_cellular_networks_provider.h"
@@ -33,9 +37,11 @@
 #include "components/user_manager/scoped_user_manager.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
+#include "ui/message_center/message_center.h"
 
 namespace ash {
 
@@ -80,29 +86,34 @@
 constexpr char kAttachAccessPointName[] = "apn_attach_access_point_name";
 constexpr char kDefaultAccessPointName[] = "apn_default_access_point_name";
 
+constexpr char kProfileName[] = "user@gmail.com";
+constexpr char kGaiaId[] = "1234567890";
+
 }  // namespace
 
-class ApnMigratorTest : public testing::Test {
+class ApnMigratorTest : public AshTestBase {
  protected:
-  ApnMigratorTest() = default;
+  ApnMigratorTest()
+      : ash::AshTestBase(std::unique_ptr<base::test::TaskEnvironment>(
+            std::make_unique<content::BrowserTaskEnvironment>())) {}
 
   ApnMigratorTest(const ApnMigratorTest&) = delete;
   ApnMigratorTest& operator=(const ApnMigratorTest&) = delete;
   ~ApnMigratorTest() override = default;
 
-  // testing::Test
+  // AshTestBase:
   void SetUp() override {
-    // TODO(b/278643115) Remove LoginState dependency.
-    LoginState::Initialize();
+    AshTestBase::SetUp();
 
-    const AccountId account_id = AccountId::FromUserEmail("test@test");
-    auto fake_user_manager = std::make_unique<user_manager::FakeUserManager>();
+    profile_manager_ = std::make_unique<TestingProfileManager>(
+        TestingBrowserProcess::GetGlobal());
+    ASSERT_TRUE(profile_manager_->SetUp());
+    testing_profile_ = profile_manager_->CreateTestingProfile(kProfileName);
+    const AccountId account_id = AccountId::FromUserEmailGaiaId(
+        testing_profile_->GetProfileUserName(), kGaiaId);
+    auto fake_user_manager = std::make_unique<ash::FakeChromeUserManager>();
     fake_user_manager->AddUser(account_id);
-    fake_user_manager->UserLoggedIn(
-        account_id,
-        user_manager::FakeUserManager::GetFakeUsernameHash(account_id),
-        /*browser_restart=*/false,
-        /*is_child=*/false);
+    fake_user_manager->LoginUser(account_id);
     scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
         std::move(fake_user_manager));
 
@@ -135,7 +146,10 @@
     managed_network_configuration_handler_.reset();
     managed_cellular_pref_handler_.reset();
     scoped_user_manager_.reset();
-    LoginState::Shutdown();
+    profile_manager_->DeleteTestingProfile(kProfileName);
+    testing_profile_ = nullptr;
+    profile_manager_.reset();
+    ash::AshTestBase::TearDown();
   }
 
   void TriggerNetworkListChanged() {
@@ -188,12 +202,16 @@
   base::HistogramTester& histogram_tester() { return histogram_tester_; }
 
  private:
-  base::test::SingleThreadTaskEnvironment task_environment_;
   NetworkStateTestHelper network_state_helper_{
       /*use_default_devices_and_services=*/true};
   NetworkHandlerTestHelper handler_test_helper_;
   FakeStubCellularNetworksProvider stub_cellular_networks_provider_;
 
+  raw_ptr<FakeChromeUserManager> user_manager_ = nullptr;
+  std::unique_ptr<TestingProfileManager> profile_manager_;
+  raw_ptr<TestingProfile, DanglingUntriaged | ExperimentalAsh>
+      testing_profile_ = nullptr;
+
   std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
 
   std::unique_ptr<MockManagedCellularPrefHandler>
@@ -281,6 +299,7 @@
   // Invoke the function again. |cellular_service_path_1|'s property shouldn't
   // be attempted to be cleared again.
   TriggerNetworkListChanged();
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
 }
 
 TEST_F(ApnMigratorTest, AlreadyMigratedNetworks) {
@@ -474,6 +493,7 @@
   // The revamp APN lists will not be sent to any of the networks in shill as
   // they have all been successfully sent now.
   TriggerNetworkListChanged();
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
 }
 
 TEST_F(ApnMigratorTest, MigrateNetworksWithoutCustomApns) {
@@ -545,6 +565,7 @@
 
   // Function under test.
   TriggerNetworkListChanged();
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
 }
 
 TEST_F(ApnMigratorTest, MigrateNetworkAlreadyMigrating) {
@@ -639,6 +660,7 @@
           })));
   // Function under test.
   TriggerNetworkListChanged();
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
 }
 
 TEST_F(ApnMigratorTest, MigrateNetworkNoPropertiesOrNotFound) {
@@ -719,6 +741,7 @@
   std::move(get_managed_properties_callback)
       .Run(cellular_service_path_1, /*properties=*/base::Value::Dict(),
            /*error=*/absl::nullopt);
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
 }
 
 TEST_F(ApnMigratorTest, MigrateNetworkCustomApnRemovedDuringMigration) {
@@ -835,6 +858,7 @@
            /*error=*/absl::nullopt);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(GetCustomApns().empty());
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
 }
 
 TEST_F(
@@ -952,6 +976,8 @@
            /*error=*/absl::nullopt);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(GetCustomApns().empty());
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsManagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::ManagedApnMigrationType::
@@ -1024,6 +1050,8 @@
   EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
   EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsManagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::ManagedApnMigrationType::
@@ -1110,6 +1138,8 @@
   EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
@@ -1185,6 +1215,8 @@
   EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
   EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
@@ -1260,11 +1292,19 @@
   EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
   EXPECT_EQ(ApnState::kDisabled, custom_apns[0]->state);
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
+  EXPECT_EQ(1u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
           kDoesNotMatchLastGoodApn,
       1);
+  const std::string notification_id =
+      ApnMigrator::kShowApnConfigurationDisabledNotificationIdPrefix +
+      std::string(kTestCellularGuid1);
+  message_center::MessageCenter::Get()->ClickOnNotification(notification_id);
+
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
 }
 
 TEST_F(ApnMigratorTest,
@@ -1338,6 +1378,8 @@
   EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
@@ -1414,6 +1456,8 @@
   EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
   EXPECT_FALSE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
@@ -1493,6 +1537,8 @@
   EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
   EXPECT_FALSE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
@@ -1585,6 +1631,8 @@
   EXPECT_EQ(kDefaultAccessPointName, custom_apns[0]->access_point_name);
   EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
@@ -1664,6 +1712,8 @@
   EXPECT_EQ(kAttachAccessPointName, custom_apns[0]->access_point_name);
   EXPECT_EQ(ApnState::kDisabled, custom_apns[0]->state);
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
@@ -1738,6 +1788,8 @@
   EXPECT_EQ(ApnState::kDisabled, custom_apns[0]->state);
   EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
   EXPECT_EQ(1u, custom_apns[0]->apn_types.size());
+  EXPECT_EQ(0u, message_center::MessageCenter::Get()->NotificationCount());
+
   histogram_tester().ExpectBucketCount(
       CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
       CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 50334aa..8e3cd8b 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -2975,7 +2975,6 @@
 
 // Test that we do not fill formless non-checkout forms when we enable the
 // formless form restrictions.
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestBase, AllAutocomplete) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3258,7 +3257,6 @@
 };
 
 // Test that we can Autofill dynamically generated forms.
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill) {
   CreateTestProfile();
@@ -3281,7 +3279,6 @@
   EXPECT_EQ("15125551234", GetFieldValueById("phone_form1"));
 }
 
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        TwoDynamicChangingFormsFill) {
   CreateTestProfile();
@@ -3365,7 +3362,6 @@
 }
 
 // Test that only field of a type group that was filled initially get refilled.
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_AddsNewFieldTypeGroups) {
   CreateTestProfile();
@@ -3421,7 +3417,6 @@
 
 // Test that we can autofill forms that dynamically change the visibility of a
 // field after it's autofilled.
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicFormFill_VisibilitySwitch) {
   CreateTestProfile();
@@ -3471,7 +3466,6 @@
 
 // Test that we can autofill forms that dynamically change the element that
 // has been clicked on, even though the form has no name.
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicFormFill_FirstElementDisappearsNoNameForm) {
   CreateTestProfile();
@@ -3550,7 +3544,6 @@
 
 // Test that we can autofill forms that dynamically change the element that
 // has been clicked on, even though there are multiple forms with no name.
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(
     AutofillInteractiveTestDynamicForm,
     DynamicFormFill_FirstElementDisappearsMultipleNoNameForms) {
@@ -3767,7 +3760,6 @@
 // Test that we can Autofill dynamically changing selects that have options
 // added and removed for forms with no names if the NameForAutofill of the first
 // field matches.
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_SelectUpdated_FormWithoutName) {
   CreateTestProfile();
@@ -3793,7 +3785,6 @@
 
 // Test that we can Autofill dynamically generated synthetic forms if the
 // NameForAutofill of the first field matches.
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_SyntheticForm) {
   CreateTestProfile();
@@ -3819,7 +3810,6 @@
 
 // Test that we can Autofill dynamically synthetic forms when the select options
 // change if the NameForAutofill of the first field matches
-// TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
 IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_SelectUpdated_SyntheticForm) {
   CreateTestProfile();
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.cc b/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.cc
index 948ac4b..bce60f7 100644
--- a/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.cc
+++ b/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.cc
@@ -141,9 +141,10 @@
 ServiceWorkerLifetimeManagerFactory::~ServiceWorkerLifetimeManagerFactory() =
     default;
 
-KeyedService* ServiceWorkerLifetimeManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ServiceWorkerLifetimeManagerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new ServiceWorkerLifetimeManager(context);
+  return std::make_unique<ServiceWorkerLifetimeManager>(context);
 }
 
 }  // namespace extensions::file_system_provider
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.h b/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.h
index 9c7f7764..c221869c 100644
--- a/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.h
+++ b/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.h
@@ -45,6 +45,7 @@
 // are requests in progress.
 class ServiceWorkerLifetimeManager : public KeyedService {
  public:
+  explicit ServiceWorkerLifetimeManager(content::BrowserContext*);
   ServiceWorkerLifetimeManager(const ServiceWorkerLifetimeManager&) = delete;
   ServiceWorkerLifetimeManager& operator=(const ServiceWorkerLifetimeManager&) =
       delete;
@@ -82,8 +83,6 @@
     bool operator<(const KeepaliveKey& other) const;
   };
 
-  explicit ServiceWorkerLifetimeManager(content::BrowserContext*);
-
   // Virtual for tests.
   virtual std::string IncrementKeepalive(const WorkerId&);
   virtual void DecrementKeepalive(const KeepaliveKey&);
@@ -119,7 +118,7 @@
   ~ServiceWorkerLifetimeManagerFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/extensions/chrome_extension_cookies.h b/chrome/browser/extensions/chrome_extension_cookies.h
index 83bcfb3..f40b741 100644
--- a/chrome/browser/extensions/chrome_extension_cookies.h
+++ b/chrome/browser/extensions/chrome_extension_cookies.h
@@ -47,6 +47,8 @@
       public content_settings::Observer,
       public content_settings::CookieSettings::Observer {
  public:
+  explicit ChromeExtensionCookies(Profile* profile);
+  ~ChromeExtensionCookies() override;
   ChromeExtensionCookies(const ChromeExtensionCookies&) = delete;
   ChromeExtensionCookies& operator=(const ChromeExtensionCookies&) = delete;
 
@@ -133,9 +135,6 @@
     base::WeakPtrFactory<IOData> weak_factory_{this};
   };
 
-  explicit ChromeExtensionCookies(Profile* profile);
-  ~ChromeExtensionCookies() override;
-
   // content_settings::Observer:
   void OnContentSettingChanged(
       const ContentSettingsPattern& primary_pattern,
diff --git a/chrome/browser/extensions/chrome_extension_cookies_factory.cc b/chrome/browser/extensions/chrome_extension_cookies_factory.cc
index d20e7bb..dbe9797 100644
--- a/chrome/browser/extensions/chrome_extension_cookies_factory.cc
+++ b/chrome/browser/extensions/chrome_extension_cookies_factory.cc
@@ -37,9 +37,11 @@
 
 ChromeExtensionCookiesFactory::~ChromeExtensionCookiesFactory() = default;
 
-KeyedService* ChromeExtensionCookiesFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ChromeExtensionCookiesFactory::BuildServiceInstanceForBrowserContext(
     BrowserContext* context) const {
-  return new ChromeExtensionCookies(static_cast<Profile*>(context));
+  return std::make_unique<ChromeExtensionCookies>(
+      static_cast<Profile*>(context));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extension_cookies_factory.h b/chrome/browser/extensions/chrome_extension_cookies_factory.h
index 3e52781..637bb75 100644
--- a/chrome/browser/extensions/chrome_extension_cookies_factory.h
+++ b/chrome/browser/extensions/chrome_extension_cookies_factory.h
@@ -29,7 +29,7 @@
   ~ChromeExtensionCookiesFactory() override;
 
   // BrowserContextKeyedServiceFactory implementation
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/extensions/event_metrics_browsertest.cc b/chrome/browser/extensions/event_metrics_browsertest.cc
new file mode 100644
index 0000000..9122d19
--- /dev/null
+++ b/chrome/browser/extensions/event_metrics_browsertest.cc
@@ -0,0 +1,112 @@
+// Copyright 2023 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/extensions/extension_browsertest.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Stores variable information for event metric parameterized testing.
+struct EventMetricTestData {
+  // The folder the extension should be loaded from.
+  const std::string extension_test_data_folder;
+  // The metric that we expected to be emitted.
+  const std::string event_metric_emitted;
+  // The metric(s) that we expect to not be emitted.
+  std::vector<std::string> event_metrics_not_emitted;
+};
+
+// Generates the parameterized test data for the DispatchToSendToRenderer metric
+// test.
+const std::vector<EventMetricTestData>& GetDispatchToSendToRendererTestData() {
+  static base::NoDestructor<std::vector<EventMetricTestData>> test_data(
+      {{/*extension_test_data_folder=*/"persistent_background_page",
+        /*event_metric=*/
+        "Extensions.Events.DispatchToSendToRenderer."
+        "ExtensionPersistentBackgroundPage",
+        /*event_metrics_not_emitted=*/
+        {"Extensions.Events.DispatchToSendToRenderer.ExtensionEventPage",
+         "Extensions.Events.DispatchToSendToRenderer.ExtensionServiceWorker"}},
+       {/*extension_test_data_folder=*/"event_page",
+        /*event_metric=*/
+        "Extensions.Events.DispatchToSendToRenderer.ExtensionEventPage",
+        /*event_metrics_not_emitted=*/
+        {"Extensions.Events.DispatchToSendToRenderer."
+         "ExtensionPersistentBackgroundPage",
+         "Extensions.Events.DispatchToSendToRenderer.ExtensionServiceWorker"}},
+       {/*extension_test_data_folder=*/"service_worker",
+        /*event_metric=*/
+        "Extensions.Events.DispatchToSendToRenderer.ExtensionServiceWorker",
+        /*event_metrics_not_emitted=*/
+        {"Extensions.Events.DispatchToSendToRenderer.ExtensionEventPage",
+         "Extensions.Events.DispatchToSendToRenderer."
+         "ExtensionPersistentBackgroundPage"}}});
+
+  return *test_data;
+}
+
+}  // namespace
+
+namespace extensions {
+
+// TODO(crbug.com/1441221): Add DispatchToAck and other metrics to this suite.
+class EventMetricsBrowserTest
+    : public ExtensionBrowserTest,
+      public testing::WithParamInterface<EventMetricTestData> {
+ public:
+  EventMetricsBrowserTest() = default;
+
+  EventMetricsBrowserTest(const EventMetricsBrowserTest&) = delete;
+  EventMetricsBrowserTest& operator=(const EventMetricsBrowserTest&) = delete;
+
+  // ExtensionBrowserTest overrides:
+  void SetUpOnMainThread() override {
+    ExtensionBrowserTest::SetUpOnMainThread();
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+};
+
+// Tests the DispatchToSendToRenderer metric is emitting for each extension
+// context type and only that type.
+IN_PROC_BROWSER_TEST_P(EventMetricsBrowserTest, DispatchToSendToRenderer) {
+  base::HistogramTester histogram_tester;
+  // Load an extension that listens for webNavigation events.
+  const Extension* extension =
+      LoadExtension(test_data_dir_.AppendASCII("events/metrics/")
+                        .AppendASCII(GetParam().extension_test_data_folder));
+  ASSERT_TRUE(extension);
+
+  // Navigate somewhere to trigger the event to webNavigation.onCompleted to the
+  // extension listener.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("example.com", "/simple.html")));
+
+  const std::string& event_metric_emitted = GetParam().event_metric_emitted;
+  // Call to webNavigation.onCompleted expected.
+  histogram_tester.ExpectTotalCount(event_metric_emitted,
+                                    /*expected_count=*/1);
+
+  // Verify that the recorded values are sane -- that is, that they are less
+  // than the maximum bucket.
+  histogram_tester.ExpectBucketCount(
+      event_metric_emitted,
+      /*sample=*/base::Minutes(5).InMicroseconds(), /*expected_count=*/0);
+  // Verify other extension context types are not logged.
+  for (const auto& event_metric_not_emitted :
+       GetParam().event_metrics_not_emitted) {
+    SCOPED_TRACE(event_metric_not_emitted);
+    histogram_tester.ExpectTotalCount(event_metric_not_emitted,
+                                      /*expected_count=*/0);
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    ExtensionContextType,
+    EventMetricsBrowserTest,
+    testing::ValuesIn(GetDispatchToSendToRendererTestData()));
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/extension_sync_service_factory.cc b/chrome/browser/extensions/extension_sync_service_factory.cc
index 5c2aa1d5..a685606 100644
--- a/chrome/browser/extensions/extension_sync_service_factory.cc
+++ b/chrome/browser/extensions/extension_sync_service_factory.cc
@@ -42,7 +42,9 @@
 
 ExtensionSyncServiceFactory::~ExtensionSyncServiceFactory() = default;
 
-KeyedService* ExtensionSyncServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ExtensionSyncServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new ExtensionSyncService(Profile::FromBrowserContext(context));
+  return std::make_unique<ExtensionSyncService>(
+      Profile::FromBrowserContext(context));
 }
diff --git a/chrome/browser/extensions/extension_sync_service_factory.h b/chrome/browser/extensions/extension_sync_service_factory.h
index c3893b26..2b21643 100644
--- a/chrome/browser/extensions/extension_sync_service_factory.h
+++ b/chrome/browser/extensions/extension_sync_service_factory.h
@@ -23,7 +23,7 @@
   ExtensionSyncServiceFactory();
   ~ExtensionSyncServiceFactory() override;
 
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker_factory.cc b/chrome/browser/extensions/forced_extensions/install_stage_tracker_factory.cc
index 4303f24..34f3151 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker_factory.cc
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker_factory.cc
@@ -34,9 +34,10 @@
 
 InstallStageTrackerFactory::~InstallStageTrackerFactory() = default;
 
-KeyedService* InstallStageTrackerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+InstallStageTrackerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new InstallStageTracker(context);
+  return std::make_unique<InstallStageTracker>(context);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker_factory.h b/chrome/browser/extensions/forced_extensions/install_stage_tracker_factory.h
index 3f8f37f..b9d29ab 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker_factory.h
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker_factory.h
@@ -29,7 +29,7 @@
   InstallStageTrackerFactory();
   ~InstallStageTrackerFactory() override;
 
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/image_service/image_service_factory.cc b/chrome/browser/image_service/image_service_factory.cc
index 3cd517b8..0481557 100644
--- a/chrome/browser/image_service/image_service_factory.cc
+++ b/chrome/browser/image_service/image_service_factory.cc
@@ -47,10 +47,11 @@
 
 ImageServiceFactory::~ImageServiceFactory() = default;
 
-KeyedService* ImageServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ImageServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   auto* profile = Profile::FromBrowserContext(context);
-  return new ImageService(
+  return std::make_unique<ImageService>(
       TemplateURLServiceFactory::GetForProfile(profile),
       RemoteSuggestionsServiceFactory::GetForProfile(
           profile, /*create_if_necessary=*/true),
diff --git a/chrome/browser/image_service/image_service_factory.h b/chrome/browser/image_service/image_service_factory.h
index aa8fff1..0d18f63 100644
--- a/chrome/browser/image_service/image_service_factory.h
+++ b/chrome/browser/image_service/image_service_factory.h
@@ -34,7 +34,7 @@
   ~ImageServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.cc
index 566f7c5..cd3dee4 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.cc
@@ -36,10 +36,11 @@
   return true;
 }
 
-KeyedService* WebRtcEventLogManagerKeyedServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+  WebRtcEventLogManagerKeyedServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   DCHECK(!context->IsOffTheRecord());
-  return new WebRtcEventLogManagerKeyedService(context);
+  return std::make_unique<WebRtcEventLogManagerKeyedService>(context);
 }
 
 }  // namespace webrtc_event_logging
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.h b/chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.h
index baf2123..62c9cda9 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_keyed_service_factory.h
@@ -36,7 +36,7 @@
   WebRtcEventLogManagerKeyedServiceFactory();
   ~WebRtcEventLogManagerKeyedServiceFactory() override;
 
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/new_tab_page/modules/photos/photos_service_factory.cc b/chrome/browser/new_tab_page/modules/photos/photos_service_factory.cc
index db07a6b..14e8630 100644
--- a/chrome/browser/new_tab_page/modules/photos/photos_service_factory.cc
+++ b/chrome/browser/new_tab_page/modules/photos/photos_service_factory.cc
@@ -35,12 +35,13 @@
 
 PhotosServiceFactory::~PhotosServiceFactory() = default;
 
-KeyedService* PhotosServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+PhotosServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   auto url_loader_factory = context->GetDefaultStoragePartition()
                                 ->GetURLLoaderFactoryForBrowserProcess();
   auto* profile = Profile::FromBrowserContext(context);
-  return new PhotosService(url_loader_factory,
-                           IdentityManagerFactory::GetForProfile(profile),
-                           profile->GetPrefs());
+  return std::make_unique<PhotosService>(
+      url_loader_factory, IdentityManagerFactory::GetForProfile(profile),
+      profile->GetPrefs());
 }
diff --git a/chrome/browser/new_tab_page/modules/photos/photos_service_factory.h b/chrome/browser/new_tab_page/modules/photos/photos_service_factory.h
index ea8db53..b874e0f 100644
--- a/chrome/browser/new_tab_page/modules/photos/photos_service_factory.h
+++ b/chrome/browser/new_tab_page/modules/photos/photos_service_factory.h
@@ -23,7 +23,7 @@
   ~PhotosServiceFactory() override;
 
   // Uses BrowserContextKeyedServiceFactory to build a PhotosService.
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/notifications/notifier_state_tracker_factory.cc b/chrome/browser/notifications/notifier_state_tracker_factory.cc
index 46ec97f9..b94b1e0d 100644
--- a/chrome/browser/notifications/notifier_state_tracker_factory.cc
+++ b/chrome/browser/notifications/notifier_state_tracker_factory.cc
@@ -36,7 +36,8 @@
 
 NotifierStateTrackerFactory::~NotifierStateTrackerFactory() = default;
 
-KeyedService* NotifierStateTrackerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+NotifierStateTrackerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* profile) const {
-  return new NotifierStateTracker(static_cast<Profile*>(profile));
+  return std::make_unique<NotifierStateTracker>(static_cast<Profile*>(profile));
 }
diff --git a/chrome/browser/notifications/notifier_state_tracker_factory.h b/chrome/browser/notifications/notifier_state_tracker_factory.h
index 429bfb356..9a8fa257 100644
--- a/chrome/browser/notifications/notifier_state_tracker_factory.h
+++ b/chrome/browser/notifications/notifier_state_tracker_factory.h
@@ -26,7 +26,7 @@
   ~NotifierStateTrackerFactory() override;
 
   // BrowserContextKeyedServiceFactory implementation.
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
 };
 
diff --git a/chrome/browser/notifications/platform_notification_service_factory.cc b/chrome/browser/notifications/platform_notification_service_factory.cc
index bb61362..e8cbfc3 100644
--- a/chrome/browser/notifications/platform_notification_service_factory.cc
+++ b/chrome/browser/notifications/platform_notification_service_factory.cc
@@ -43,8 +43,9 @@
   DependsOn(ukm::UkmBackgroundRecorderFactory::GetInstance());
 }
 
-KeyedService* PlatformNotificationServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+PlatformNotificationServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new PlatformNotificationServiceImpl(
+  return std::make_unique<PlatformNotificationServiceImpl>(
       Profile::FromBrowserContext(context));
 }
diff --git a/chrome/browser/notifications/platform_notification_service_factory.h b/chrome/browser/notifications/platform_notification_service_factory.h
index c6a7673..6920cce3 100644
--- a/chrome/browser/notifications/platform_notification_service_factory.h
+++ b/chrome/browser/notifications/platform_notification_service_factory.h
@@ -27,7 +27,7 @@
   PlatformNotificationServiceFactory();
 
   // BrowserContextKeyedServiceFactory implementation.
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
 };
 
diff --git a/chrome/browser/optimization_guide/page_content_annotations_service_factory.cc b/chrome/browser/optimization_guide/page_content_annotations_service_factory.cc
index e4ecffb..68a18ee4 100644
--- a/chrome/browser/optimization_guide/page_content_annotations_service_factory.cc
+++ b/chrome/browser/optimization_guide/page_content_annotations_service_factory.cc
@@ -109,7 +109,8 @@
 PageContentAnnotationsServiceFactory::~PageContentAnnotationsServiceFactory() =
     default;
 
-KeyedService* PageContentAnnotationsServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+PageContentAnnotationsServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
 
@@ -133,7 +134,7 @@
   ZeroSuggestCacheService* zero_suggest_cache_service =
       ZeroSuggestCacheServiceFactory::GetForProfile(profile);
   if (optimization_guide_keyed_service && history_service) {
-    return new optimization_guide::PageContentAnnotationsService(
+    return std::make_unique<optimization_guide::PageContentAnnotationsService>(
         std::make_unique<ChromeAutocompleteProviderClient>(profile),
         g_browser_process->GetApplicationLocale(),
         optimization_guide_keyed_service, history_service, template_url_service,
diff --git a/chrome/browser/optimization_guide/page_content_annotations_service_factory.h b/chrome/browser/optimization_guide/page_content_annotations_service_factory.h
index 993a7138..215700b 100644
--- a/chrome/browser/optimization_guide/page_content_annotations_service_factory.h
+++ b/chrome/browser/optimization_guide/page_content_annotations_service_factory.h
@@ -44,7 +44,7 @@
   ~PageContentAnnotationsServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
   bool ServiceIsNULLWhileTesting() const override;
diff --git a/chrome/browser/payments/payment_handler_enforce_full_delegation_browsertest.cc b/chrome/browser/payments/payment_handler_enforce_full_delegation_browsertest.cc
index 39b8a1a..bb7f8c10 100644
--- a/chrome/browser/payments/payment_handler_enforce_full_delegation_browsertest.cc
+++ b/chrome/browser/payments/payment_handler_enforce_full_delegation_browsertest.cc
@@ -82,8 +82,8 @@
 }
 
 // crbug.com/1468262: Flaky test on Android.
-// crbug.com/1473404: Flaky test on ChromeOS.
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
+// crbug.com/1473404: Flaky test on ChromeOS and Windows.
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
 #define MAYBE_WhenEnabled_ShowPaymentSheet_WhenDisabled_Reject \
   DISABLED_WhenEnabled_ShowPaymentSheet_WhenDisabled_Reject
 #else
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.cc
index 0e0a976..ce2190a 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.cc
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.cc
@@ -41,8 +41,9 @@
 
 SearchPrefetchServiceFactory::~SearchPrefetchServiceFactory() = default;
 
-KeyedService* SearchPrefetchServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SearchPrefetchServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
-  return new SearchPrefetchService(profile);
+  return std::make_unique<SearchPrefetchService>(profile);
 }
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h
index ba73bfc..5f44694 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h
@@ -44,7 +44,7 @@
   ~SearchPrefetchServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/profiles/profile_theme_update_service_factory.cc b/chrome/browser/profiles/profile_theme_update_service_factory.cc
index d7b09aa..af921266 100644
--- a/chrome/browser/profiles/profile_theme_update_service_factory.cc
+++ b/chrome/browser/profiles/profile_theme_update_service_factory.cc
@@ -40,15 +40,15 @@
 
 ProfileThemeUpdateServiceFactory::~ProfileThemeUpdateServiceFactory() = default;
 
-KeyedService* ProfileThemeUpdateServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ProfileThemeUpdateServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   if (!profile_manager)
     return nullptr;  // Some tests don't have a profile manager.
 
   Profile* profile = Profile::FromBrowserContext(context);
-  return new ProfileThemeUpdateService(
+  return std::make_unique<ProfileThemeUpdateService>(
       profile, &profile_manager->GetProfileAttributesStorage());
 }
 
diff --git a/chrome/browser/profiles/profile_theme_update_service_factory.h b/chrome/browser/profiles/profile_theme_update_service_factory.h
index fb483b3f..142c779 100644
--- a/chrome/browser/profiles/profile_theme_update_service_factory.h
+++ b/chrome/browser/profiles/profile_theme_update_service_factory.h
@@ -31,7 +31,7 @@
   ~ProfileThemeUpdateServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
   bool ServiceIsNULLWhileTesting() const override;
diff --git a/chrome/browser/resources/ash/settings/BUILD.gn b/chrome/browser/resources/ash/settings/BUILD.gn
index 8ccb132b..2c93ca7c 100644
--- a/chrome/browser/resources/ash/settings/BUILD.gn
+++ b/chrome/browser/resources/ash/settings/BUILD.gn
@@ -84,6 +84,7 @@
     "date_time_page/timezone_subpage.ts",
     "device_page/audio.ts",
     "device_page/customize_button_row.ts",
+    "device_page/customize_buttons_subsection.ts",
     "device_page/customize_mouse_buttons_subpage.ts",
     "device_page/customize_pen_buttons_subpage.ts",
     "device_page/customize_tablet_buttons_subpage.ts",
diff --git a/chrome/browser/resources/ash/settings/device_page/customize_buttons_subsection.html b/chrome/browser/resources/ash/settings/device_page/customize_buttons_subsection.html
new file mode 100644
index 0000000..016a85b
--- /dev/null
+++ b/chrome/browser/resources/ash/settings/device_page/customize_buttons_subsection.html
@@ -0,0 +1,21 @@
+<style include="settings-shared input-device-settings-shared">
+  #header {
+    display: flex;
+    height: 24px;
+    padding: 12px 0;
+  }
+
+  #deviceName {
+    color: var(--cros-text-color-secondary);
+    margin-inline-start: 20px;
+  }
+</style>
+<template is="dom-repeat"
+    items="[[buttonRemappingList]]"
+    index-as="index">
+  <customize-button-row
+      button-remapping-list="[[buttonRemappingList]]"
+      remapping-index="[[index]]"
+      action-list$="[[actionList]]">
+  </customize-button-row>
+</template>
\ No newline at end of file
diff --git a/chrome/browser/resources/ash/settings/device_page/customize_buttons_subsection.ts b/chrome/browser/resources/ash/settings/device_page/customize_buttons_subsection.ts
new file mode 100644
index 0000000..55d7f52
--- /dev/null
+++ b/chrome/browser/resources/ash/settings/device_page/customize_buttons_subsection.ts
@@ -0,0 +1,56 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * 'customize-buttons-subsection' contains a list of 'customize-button-row'
+ * elements that allow users to remap buttons to actions or key combinations.
+ */
+
+import '../settings_shared.css.js';
+import './customize_button_row.js';
+
+import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
+import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './customize_buttons_subsection.html.js';
+import {ActionChoice, ButtonRemapping} from './input_device_settings_types.js';
+
+const CustomizeButtonsSubsectionElementBase = I18nMixin(PolymerElement);
+
+export class CustomizeButtonsSubsectionElement extends
+    CustomizeButtonsSubsectionElementBase {
+  static get is() {
+    return 'customize-buttons-subsection' as const;
+  }
+
+  static get template(): HTMLTemplateElement {
+    return getTemplate();
+  }
+
+  static get properties(): PolymerElementProperties {
+    return {
+      actionList: {
+        type: Array,
+      },
+
+      buttonRemappingList: {
+        type: Array,
+      },
+    };
+  }
+
+  buttonRemappingList: ButtonRemapping[];
+  actionList: ActionChoice[];
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    [CustomizeButtonsSubsectionElement.is]: CustomizeButtonsSubsectionElement;
+  }
+}
+
+customElements.define(
+    CustomizeButtonsSubsectionElement.is, CustomizeButtonsSubsectionElement);
diff --git a/chrome/browser/resources/ash/settings/device_page/customize_pen_buttons_subpage.html b/chrome/browser/resources/ash/settings/device_page/customize_pen_buttons_subpage.html
index 87d0346..57924d8 100644
--- a/chrome/browser/resources/ash/settings/device_page/customize_pen_buttons_subpage.html
+++ b/chrome/browser/resources/ash/settings/device_page/customize_pen_buttons_subpage.html
@@ -14,13 +14,8 @@
   <div id="description">[[selectedTablet.name]]</div>
 </div>
 <div class="subsection">
-  <template is="dom-repeat"
-      items="[[selectedTablet.settings.penButtonRemappings]]"
-      index-as="index">
-    <customize-button-row
-        button-remapping-list="[[selectedTablet.settings.penButtonRemappings]]"
-        remapping-index="[[index]]"
-        action-list$="[[buttonActionList_]]">
-    </customize-button-row>
-  </template>
-</div>
\ No newline at end of file
+  <customize-buttons-subsection
+      button-remapping-list="[[selectedTablet.settings.penButtonRemappings]]"
+      action-list$="[[buttonActionList_]]">
+  </customize-buttons-subsection>
+</div>
diff --git a/chrome/browser/resources/ash/settings/device_page/customize_tablet_buttons_subpage.html b/chrome/browser/resources/ash/settings/device_page/customize_tablet_buttons_subpage.html
index 02343dc..885eb320 100644
--- a/chrome/browser/resources/ash/settings/device_page/customize_tablet_buttons_subpage.html
+++ b/chrome/browser/resources/ash/settings/device_page/customize_tablet_buttons_subpage.html
@@ -14,13 +14,8 @@
   <div id="description">[[selectedTablet.name]]</div>
 </div>
 <div class="subsection">
-  <template is="dom-repeat"
-      items="[[selectedTablet.settings.tabletButtonRemappings]]"
-      index-as="index">
-    <customize-button-row
-        button-remapping-list="[[selectedTablet.settings.tabletButtonRemappings]]"
-        remapping-index="[[index]]"
-        action-list$="[[buttonActionList_]]">
-    </customize-button-row>
-  </template>
+  <customize-buttons-subsection
+      button-remapping-list="[[selectedTablet.settings.tabletButtonRemappings]]"
+      action-list$="[[buttonActionList_]]">
+  </customize-buttons-subsection>
 </div>
diff --git a/chrome/browser/resources/ash/settings/lazy_load.ts b/chrome/browser/resources/ash/settings/lazy_load.ts
index 7c6b6fe..5a283df 100644
--- a/chrome/browser/resources/ash/settings/lazy_load.ts
+++ b/chrome/browser/resources/ash/settings/lazy_load.ts
@@ -141,6 +141,7 @@
 export {TimezoneSelectorElement} from './date_time_page/timezone_selector.js';
 export {TimezoneSubpageElement} from './date_time_page/timezone_subpage.js';
 export {CustomizeButtonRowElement} from './device_page/customize_button_row.js';
+export {CustomizeButtonsSubsectionElement} from './device_page/customize_buttons_subsection.js';
 export {SettingsCustomizeMouseButtonsSubpageElement} from './device_page/customize_mouse_buttons_subpage.js';
 export {SettingsCustomizePenButtonsSubpageElement} from './device_page/customize_pen_buttons_subpage.js';
 export {SettingsCustomizeTabletButtonsSubpageElement} from './device_page/customize_tablet_buttons_subpage.js';
diff --git a/chrome/browser/resources/ash/settings/os_a11y_page/captions_subpage.ts b/chrome/browser/resources/ash/settings/os_a11y_page/captions_subpage.ts
index ef1ee19..b07a40f 100644
--- a/chrome/browser/resources/ash/settings/os_a11y_page/captions_subpage.ts
+++ b/chrome/browser/resources/ash/settings/os_a11y_page/captions_subpage.ts
@@ -141,6 +141,9 @@
 
       /**
        * List of options for the text shadow drop-down menu.
+       *
+       * These values are based on
+       * https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/resources/ash/settings/a11y_page/captions_subpage.ts;l=142;drc=0918c7f73782a9575396f0c6b80a722b5a3d255a
        */
       textShadowOptions_: {
         readOnly: true,
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/add_input_methods_dialog.ts b/chrome/browser/resources/ash/settings/os_languages_page/add_input_methods_dialog.ts
index f8b7df7..4bf2900 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/add_input_methods_dialog.ts
+++ b/chrome/browser/resources/ash/settings/os_languages_page/add_input_methods_dialog.ts
@@ -9,6 +9,7 @@
 
 import './add_items_dialog.js';
 
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {recordSettingChange} from '../metrics_recorder.js';
@@ -41,6 +42,10 @@
   languages: LanguagesModel|undefined;
   languageHelper: LanguageHelper;
 
+  // Internal state.
+  private readonly shouldPrioritiseVietnameseExtensions_ =
+      !loadTimeData.getBoolean('allowFirstPartyVietnameseInput');
+
   /**
    * Get suggested input methods based on user's enabled languages and ARC IMEs
    */
@@ -51,17 +56,20 @@
     ];
     let inputMethods =
         this.languageHelper.getInputMethodsForLanguages(languageCodes);
-    // Temporary solution for b/237492047: move Vietnamese extension input
-    // methods to the top of the suggested list.
-    // TODO(b/237492047): Remove this once 1P Vietnamese input methods are
-    // suitable for widespread use.
-    const isVietnameseExtension =
-        (inputMethod: chrome.languageSettingsPrivate.InputMethod): boolean =>
-            (inputMethod.id.startsWith('_ext_ime_') &&
-             inputMethod.languageCodes.includes('vi'));
-    inputMethods = inputMethods.filter(isVietnameseExtension)
-                       .concat(inputMethods.filter(
-                           inputMethod => !isVietnameseExtension(inputMethod)));
+    if (this.shouldPrioritiseVietnameseExtensions_) {
+      // Temporary solution for b/237492047: move Vietnamese extension input
+      // methods to the top of the suggested list.
+      // TODO(b/237492047): Remove this once 1P Vietnamese input methods are
+      // launched.
+      const isVietnameseExtension =
+          (inputMethod: chrome.languageSettingsPrivate.InputMethod): boolean =>
+              (inputMethod.id.startsWith('_ext_ime_') &&
+               inputMethod.languageCodes.includes('vi'));
+      inputMethods =
+          inputMethods.filter(isVietnameseExtension)
+              .concat(inputMethods.filter(
+                  inputMethod => !isVietnameseExtension(inputMethod)));
+    }
     return inputMethods.map(inputMethod => inputMethod.id);
   }
 
diff --git a/chrome/browser/resources/nearby_internals/OWNERS b/chrome/browser/resources/nearby_internals/OWNERS
index b76a3f65..6e0dc9e0 100644
--- a/chrome/browser/resources/nearby_internals/OWNERS
+++ b/chrome/browser/resources/nearby_internals/OWNERS
@@ -1,2 +1,4 @@
 file://chrome/browser/nearby_sharing/OWNERS
 khorimoto@chromium.org
+julietlevesque@google.com
+akingsb@google.com
diff --git a/chrome/browser/resources/settings/a11y_page/captions_subpage.ts b/chrome/browser/resources/settings/a11y_page/captions_subpage.ts
index dc8e71a..f03c8d96 100644
--- a/chrome/browser/resources/settings/a11y_page/captions_subpage.ts
+++ b/chrome/browser/resources/settings/a11y_page/captions_subpage.ts
@@ -154,6 +154,12 @@
 
       /**
        * List of options for the text shadow drop-down menu.
+       *
+       * Other clients are relying on these values to determine text shadow type
+       * from preference. Please update the following files if any of these
+       * values are changed:
+       * https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/resources/ash/settings/os_a11y_page/captions_subpage.ts;l=142-170;drc=0918c7f73782a9575396f0c6b80a722b5a3d255a
+       * https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ash/arc/intent_helper/arc_settings_service.cc;l=86-94;drc=a782e6ac5124014b8473c9e7e445d799624b532c
        */
       textShadowOptions_: {
         readOnly: true,
diff --git a/chrome/browser/sessions/exit_type_service.h b/chrome/browser/sessions/exit_type_service.h
index 949a0b69..c6713cd 100644
--- a/chrome/browser/sessions/exit_type_service.h
+++ b/chrome/browser/sessions/exit_type_service.h
@@ -64,6 +64,7 @@
     raw_ptr<ExitTypeService> service_;
   };
 
+  explicit ExitTypeService(Profile* profile);
   ExitTypeService(const ExitTypeService&) = delete;
   ExitTypeService& operator=(const ExitTypeService&) = delete;
   ~ExitTypeService() override;
@@ -115,8 +116,6 @@
   friend class ExitTypeServiceFactory;
   class BrowserTabObserverImpl;
 
-  explicit ExitTypeService(Profile* profile);
-
   // Checks if the user acknowledged the crash.
   void CheckUserAckedCrash();
 
diff --git a/chrome/browser/sessions/exit_type_service_factory.cc b/chrome/browser/sessions/exit_type_service_factory.cc
index 2bd427c..a9ead4a 100644
--- a/chrome/browser/sessions/exit_type_service_factory.cc
+++ b/chrome/browser/sessions/exit_type_service_factory.cc
@@ -34,7 +34,8 @@
 
 ExitTypeServiceFactory::~ExitTypeServiceFactory() = default;
 
-KeyedService* ExitTypeServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ExitTypeServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   // TODO(sky): is this necessary?
@@ -42,7 +43,7 @@
   if (ash::ProfileHelper::IsSigninProfile(profile))
     return nullptr;
 #endif
-  return new ExitTypeService(profile);
+  return std::make_unique<ExitTypeService>(profile);
 }
 
 bool ExitTypeServiceFactory::ServiceIsCreatedWithBrowserContext() const {
diff --git a/chrome/browser/sessions/exit_type_service_factory.h b/chrome/browser/sessions/exit_type_service_factory.h
index 100f68f8..aca1388 100644
--- a/chrome/browser/sessions/exit_type_service_factory.h
+++ b/chrome/browser/sessions/exit_type_service_factory.h
@@ -25,7 +25,7 @@
   ~ExitTypeServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
 };
diff --git a/chrome/browser/sessions/session_service_factory.cc b/chrome/browser/sessions/session_service_factory.cc
index 0a657d5..0749ea7 100644
--- a/chrome/browser/sessions/session_service_factory.cc
+++ b/chrome/browser/sessions/session_service_factory.cc
@@ -69,9 +69,11 @@
 
 SessionServiceFactory::~SessionServiceFactory() = default;
 
-KeyedService* SessionServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SessionServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* profile) const {
-  SessionService* service = new SessionService(static_cast<Profile*>(profile));
+  std::unique_ptr<SessionService> service =
+      std::make_unique<SessionService>(static_cast<Profile*>(profile));
   service->ResetFromCurrentBrowsers();
   return service;
 }
diff --git a/chrome/browser/sessions/session_service_factory.h b/chrome/browser/sessions/session_service_factory.h
index df41f51..efd3c8c 100644
--- a/chrome/browser/sessions/session_service_factory.h
+++ b/chrome/browser/sessions/session_service_factory.h
@@ -66,7 +66,7 @@
   ~SessionServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
   bool ServiceIsNULLWhileTesting() const override;
diff --git a/chrome/browser/speech/speech_recognition_client_browser_interface_factory.cc b/chrome/browser/speech/speech_recognition_client_browser_interface_factory.cc
index 58c630d..6d411c4 100644
--- a/chrome/browser/speech/speech_recognition_client_browser_interface_factory.cc
+++ b/chrome/browser/speech/speech_recognition_client_browser_interface_factory.cc
@@ -46,10 +46,11 @@
 SpeechRecognitionClientBrowserInterfaceFactory::
     ~SpeechRecognitionClientBrowserInterfaceFactory() = default;
 
-KeyedService*
-SpeechRecognitionClientBrowserInterfaceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return new speech::SpeechRecognitionClientBrowserInterface(context);
+std::unique_ptr<KeyedService> SpeechRecognitionClientBrowserInterfaceFactory::
+    BuildServiceInstanceForBrowserContext(
+        content::BrowserContext* context) const {
+  return std::make_unique<speech::SpeechRecognitionClientBrowserInterface>(
+      context);
 }
 
 // static
diff --git a/chrome/browser/speech/speech_recognition_client_browser_interface_factory.h b/chrome/browser/speech/speech_recognition_client_browser_interface_factory.h
index fe071ac34..e165863 100644
--- a/chrome/browser/speech/speech_recognition_client_browser_interface_factory.h
+++ b/chrome/browser/speech/speech_recognition_client_browser_interface_factory.h
@@ -33,7 +33,7 @@
   ~SpeechRecognitionClientBrowserInterfaceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/speech/speech_recognition_service_factory.cc b/chrome/browser/speech/speech_recognition_service_factory.cc
index 09fdaf4..caff1289 100644
--- a/chrome/browser/speech/speech_recognition_service_factory.cc
+++ b/chrome/browser/speech/speech_recognition_service_factory.cc
@@ -37,9 +37,10 @@
 
 SpeechRecognitionServiceFactory::~SpeechRecognitionServiceFactory() = default;
 
-KeyedService* SpeechRecognitionServiceFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SpeechRecognitionServiceFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new speech::ChromeSpeechRecognitionService(context);
+  return std::make_unique<speech::ChromeSpeechRecognitionService>(context);
 }
 
 // static
diff --git a/chrome/browser/speech/speech_recognition_service_factory.h b/chrome/browser/speech/speech_recognition_service_factory.h
index 4896a2c..e73fa12 100644
--- a/chrome/browser/speech/speech_recognition_service_factory.h
+++ b/chrome/browser/speech/speech_recognition_service_factory.h
@@ -30,7 +30,7 @@
   ~SpeechRecognitionServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 041d310d..046e33d 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -357,7 +357,7 @@
         No preloading
       </message>
       <message name="IDS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY" desc="Short explanation of what the no preloading mode does in the Preload Pages setting.">
-        Pages load only after you open them.
+        Pages load only after you open them
       </message>
       <message name="IDS_PRELOAD_PAGES_STANDARD_PRELOADING_TITLE" desc="Name of the standard preloading option for the Preload Pages settings page. This option enables preloading pages that Chrome believes the user is likely to navigate to. [CHAR_LIMIT=32]">
         Standard preloading
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY.png.sha1
index 1d19dac..a66e5c1 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY.png.sha1
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PRELOAD_PAGES_NO_PRELOADING_SUMMARY.png.sha1
@@ -1 +1 @@
-c7457665040a0c617b6011560342d39c754e6c62
\ No newline at end of file
+757fcd1b878a69019c4299e787a83590ad1aeed6
\ No newline at end of file
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index cfe2d814..6a8fe1a 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -483,13 +483,13 @@
   // updating the CVC unmask prompt with the error message.
   switch (result) {
     case AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure:
-      ShowVirtualCardErrorDialog(
-          AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+      ShowAutofillErrorDialog(
+          AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
               /*is_permanent_error=*/true));
       break;
     case AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure:
-      ShowVirtualCardErrorDialog(
-          AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+      ShowAutofillErrorDialog(
+          AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
               /*is_permanent_error=*/false));
       break;
     case AutofillClient::PaymentsRpcResult::kSuccess:
@@ -1075,7 +1075,7 @@
 #endif
 }
 
-void ChromeAutofillClient::ShowVirtualCardErrorDialog(
+void ChromeAutofillClient::ShowAutofillErrorDialog(
     const AutofillErrorDialogContext& context) {
   autofill_error_dialog_controller_.Show(context);
 }
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index b0b821c6..47ac2221 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -247,7 +247,7 @@
   void DismissOfferNotification() override;
   void OnVirtualCardDataAvailable(
       const VirtualCardManualFallbackBubbleOptions& options) override;
-  void ShowVirtualCardErrorDialog(
+  void ShowAutofillErrorDialog(
       const AutofillErrorDialogContext& context) override;
   void ShowAutofillProgressDialog(
       AutofillProgressDialogType autofill_progress_dialog_type,
diff --git a/chrome/browser/ui/safety_hub/safety_hub_service.cc b/chrome/browser/ui/safety_hub/safety_hub_service.cc
index ad2e8e3..4b01b73 100644
--- a/chrome/browser/ui/safety_hub/safety_hub_service.cc
+++ b/chrome/browser/ui/safety_hub/safety_hub_service.cc
@@ -7,11 +7,11 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/task/thread_pool.h"
+#include "base/time/time.h"
 #include "content/public/browser/browser_thread.h"
 
 SafetyHubService::Result::Result(base::TimeTicks timestamp)
     : timestamp_(timestamp) {}
-SafetyHubService::Result::~Result() = default;
 
 base::TimeTicks SafetyHubService::Result::timestamp() const {
   return timestamp_;
@@ -26,7 +26,11 @@
 
 void SafetyHubService::StartRepeatedUpdates() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  UpdateAsync();
+  // TODO(crbug.com/1443466): the 10 minute delay is a workaround of the task
+  // being posted to a different thread. This should be removed.
+  delay_timer_.Start(
+      FROM_HERE, base::Minutes(10),
+      base::BindOnce(&SafetyHubService::UpdateAsync, GetAsWeakRef()));
   update_timer_.Start(FROM_HERE, GetRepeatedUpdateInterval(),
                       base::BindRepeating(&SafetyHubService::UpdateAsync,
                                           base::Unretained(this)));
@@ -38,7 +42,7 @@
       FROM_HERE, {base::TaskPriority::BEST_EFFORT},
       base::BindOnce(&SafetyHubService::UpdateOnBackgroundThread,
                      base::Unretained(this)),
-      base::BindOnce(&SafetyHubService::OnUpdateFinished, AsWeakPtr()));
+      base::BindOnce(&SafetyHubService::OnUpdateFinished, GetAsWeakRef()));
 }
 
 void SafetyHubService::OnUpdateFinished(std::unique_ptr<Result> result) {
@@ -59,3 +63,8 @@
     observer.OnResultAvailable(result);
   }
 }
+
+std::unique_ptr<SafetyHubService::Result>
+SafetyHubService::UpdateOnBackgroundThreadForTesting() {
+  return UpdateOnBackgroundThread();
+}
diff --git a/chrome/browser/ui/safety_hub/safety_hub_service.h b/chrome/browser/ui/safety_hub/safety_hub_service.h
index e372b34..72eb1cc 100644
--- a/chrome/browser/ui/safety_hub/safety_hub_service.h
+++ b/chrome/browser/ui/safety_hub/safety_hub_service.h
@@ -31,7 +31,7 @@
 
     Result(const Result&) = delete;
     Result& operator=(const Result&) = delete;
-    ~Result();
+    virtual ~Result() = default;
 
     base::TimeTicks timestamp() const;
 
@@ -52,13 +52,6 @@
 
   ~SafetyHubService() override;
 
-  // KeyedService implementation.
-  void Shutdown() override;
-
-  // Triggers the repeated update task that updates the state of the Safety Hub
-  // service.
-  void StartRepeatedUpdates();
-
   // Makes an asynchronous call to the Update function, and will call the
   // callback function upon completion.
   void UpdateAsync();
@@ -69,11 +62,19 @@
   // Removes an observer from the observer list.
   void RemoveObserver(Observer* observer);
 
-  void SetClockForTesting(std::unique_ptr<base::Clock> clock) {
-    clock_for_testing_ = std::move(clock);
-  }
+  // KeyedService implementation.
+  void Shutdown() override;
+
+  // Public version of UpdateOnBackgroundThread for testing purposes.
+  std::unique_ptr<Result> UpdateOnBackgroundThreadForTesting();
 
  protected:
+  // Triggers the repeated update task that updates the state of the Safety Hub
+  // service.
+  void StartRepeatedUpdates();
+
+  // SafetyHubService overrides.
+
   // The value returned by this function determines the interval of how often
   // the Update function will be called.
   virtual base::TimeDelta GetRepeatedUpdateInterval() = 0;
@@ -82,13 +83,11 @@
   // service.
   virtual std::unique_ptr<Result> UpdateOnBackgroundThread() = 0;
 
-  base::Clock* GetClock() {
-    return clock_for_testing_ ? clock_for_testing_.get()
-                              : base::DefaultClock::GetInstance();
-  }
+  virtual base::WeakPtr<SafetyHubService> GetAsWeakRef() = 0;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(SafetyHubServiceTest, ManageObservers);
+  FRIEND_TEST_ALL_PREFIXES(SafetyHubServiceTest, UpdateOnBackgroundThread);
 
   // Called as soon as the update has been finished.
   void OnUpdateFinished(std::unique_ptr<Result> result);
@@ -99,11 +98,11 @@
   // Repeating timer that runs the recurring tasks.
   base::RepeatingTimer update_timer_;
 
+  // Timer used to delay the execution of the initial task with several minutes.
+  base::OneShotTimer delay_timer_;
+
   // List of observers that have to be notified when a new result is available.
   base::ObserverList<Observer> observers_;
-
-  // Clock used in testing.
-  std::unique_ptr<base::Clock> clock_for_testing_;
 };
 
 #endif  // CHROME_BROWSER_UI_SAFETY_HUB_SAFETY_HUB_SERVICE_H_
diff --git a/chrome/browser/ui/safety_hub/safety_hub_service_unittest.cc b/chrome/browser/ui/safety_hub/safety_hub_service_unittest.cc
index fd322de..ad19a626 100644
--- a/chrome/browser/ui/safety_hub/safety_hub_service_unittest.cc
+++ b/chrome/browser/ui/safety_hub/safety_hub_service_unittest.cc
@@ -17,6 +17,11 @@
 namespace {
 constexpr base::TimeDelta kUpdateIntervalForTest = base::Days(7);
 
+class MockSafetyHubResult : public SafetyHubService::Result {
+ public:
+  ~MockSafetyHubResult() override = default;
+};
+
 class MockSafetyHubService : public SafetyHubService {
  public:
   // Returns the number of times that the UpdateOnBackgroundThread function was
@@ -32,11 +37,17 @@
 
   std::unique_ptr<Result> UpdateOnBackgroundThread() override {
     ++num_updates_;
-    return std::make_unique<Result>();
+    return std::make_unique<MockSafetyHubResult>();
+  }
+
+  base::WeakPtr<SafetyHubService> GetAsWeakRef() override {
+    return weak_factory_.GetWeakPtr();
   }
 
  private:
   int num_updates_ = 0;
+
+  base::WeakPtrFactory<MockSafetyHubService> weak_factory_{this};
 };
 
 class MockObserver : public SafetyHubService::Observer {
@@ -88,7 +99,7 @@
   // observers, but should not be called yet.
   EXPECT_TRUE(service()->observers_.HasObserver(observer.get()));
   EXPECT_EQ(observer->GetNumCalls(), 0);
-  auto result = std::make_unique<SafetyHubService::Result>();
+  auto result = std::make_unique<MockSafetyHubResult>();
   // Notify all observers.
   service()->NotifyObservers(result.get());
   // Ensure that the observer was called just once.
@@ -113,6 +124,9 @@
   // The update will be run asynchronously as soon as StartRepeatedUpdates() is
   // called.
   service()->StartRepeatedUpdates();
+  // TODO(tov): When we remove the delay for running the repeated updates, this
+  // should be removed.
+  FastForwardBy(base::Minutes(15));
   RunUntilIdle();
   EXPECT_EQ(service()->GetNumUpdates(), 1);
   // Move forward a full update interval, which will trigger another update.
diff --git a/chrome/browser/ui/safety_hub/unused_site_permissions_service.cc b/chrome/browser/ui/safety_hub/unused_site_permissions_service.cc
index 029b567..24e2a04 100644
--- a/chrome/browser/ui/safety_hub/unused_site_permissions_service.cc
+++ b/chrome/browser/ui/safety_hub/unused_site_permissions_service.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/ui/safety_hub/unused_site_permissions_service.h"
 
+#include <memory>
+
 #include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/run_loop.h"
@@ -48,42 +51,6 @@
 // |kAllowAgainMetricsExclusiveMaxCount|.
 size_t kAllowAgainMetricsBuckets = 31;
 
-// Called on a background thread.
-UnusedSitePermissionsService::UnusedPermissionMap GetUnusedPermissionsMap(
-    base::Clock* clock,
-    scoped_refptr<HostContentSettingsMap> hcsm) {
-  UnusedSitePermissionsService::UnusedPermissionMap recently_unused;
-  base::Time threshold =
-      clock->Now() - content_settings::GetCoarseVisitedTimePrecision();
-
-  auto* registry = content_settings::ContentSettingsRegistry::GetInstance();
-  for (const content_settings::ContentSettingsInfo* info : *registry) {
-    ContentSettingsType type = info->website_settings_info()->type();
-    if (!content_settings::CanTrackLastVisit(type)) {
-      continue;
-    }
-    for (const auto& setting : hcsm->GetSettingsForOneType(type)) {
-      // Skip wildcard patterns that don't belong to a single origin. These
-      // shouldn't track visit timestamps.
-      if (!setting.primary_pattern.MatchesSingleOrigin()) {
-        continue;
-      }
-      if (setting.metadata.last_visited() != base::Time() &&
-          setting.metadata.last_visited() < threshold) {
-        GURL url = GURL(setting.primary_pattern.ToString());
-        // Converting URL to a origin is normally an anti-pattern but here it is
-        // ok since the URL belongs to a single origin. Therefore, it has a
-        // fully defined URL+scheme+port which makes converting URL to origin
-        // successful.
-        url::Origin origin = url::Origin::Create(url);
-        recently_unused[origin.Serialize()].push_back(
-            {type, std::move(setting)});
-      }
-    }
-  }
-  return recently_unused;
-}
-
 base::TimeDelta GetRevocationThreshold() {
   // TODO(crbug.com/1401701): Clean up no delay revocation after the feature is
   // ready. Today, no delay revocation is necessary to enable manual testing.
@@ -111,16 +78,57 @@
 
 }  // namespace
 
+base::TimeDelta UnusedSitePermissionsService::GetRepeatedUpdateInterval() {
+  return content_settings::features::
+      kSafetyCheckUnusedSitePermissionsRepeatedUpdateInterval.Get();
+}
+
 UnusedSitePermissionsService::TabHelper::TabHelper(
     content::WebContents* web_contents,
     UnusedSitePermissionsService* unused_site_permission_service)
     : content::WebContentsObserver(web_contents),
       content::WebContentsUserData<TabHelper>(*web_contents),
       unused_site_permission_service_(
-          unused_site_permission_service->AsWeakPtr()) {}
+          base::AsWeakPtr(unused_site_permission_service)) {}
 
 UnusedSitePermissionsService::TabHelper::~TabHelper() = default;
 
+UnusedSitePermissionsService::RevokedPermission::RevokedPermission(
+    ContentSettingsPattern origin,
+    std::set<ContentSettingsType> permission_types,
+    base::Time expiration)
+    : origin(origin),
+      permission_types(permission_types),
+      expiration(expiration) {}
+
+UnusedSitePermissionsService::RevokedPermission::~RevokedPermission() = default;
+
+UnusedSitePermissionsService::RevokedPermission::RevokedPermission(
+    const RevokedPermission&) = default;
+
+UnusedSitePermissionsService::UnusedSitePermissionsResult::
+    UnusedSitePermissionsResult() = default;
+UnusedSitePermissionsService::UnusedSitePermissionsResult::
+    ~UnusedSitePermissionsResult() = default;
+
+void UnusedSitePermissionsService::UnusedSitePermissionsResult::
+    AddRevokedPermission(ContentSettingsPattern origin,
+                         std::set<ContentSettingsType> permission_types,
+                         base::Time expiration) {
+  RevokedPermission revoked_permission(std::move(origin),
+                                       std::set<ContentSettingsType>(),
+                                       std::move(expiration));
+  revoked_permissions_.push_back(std::move(revoked_permission));
+}
+
+std::list<UnusedSitePermissionsService::RevokedPermission>
+UnusedSitePermissionsService::UnusedSitePermissionsResult::
+    GetRevokedPermissions() {
+  std::list<UnusedSitePermissionsService::RevokedPermission> result(
+      revoked_permissions_);
+  return result;
+}
+
 void UnusedSitePermissionsService::TabHelper::PrimaryPageChanged(
     content::Page& page) {
   if (unused_site_permission_service_) {
@@ -136,6 +144,7 @@
     : hcsm_(hcsm), clock_(base::DefaultClock::GetInstance()) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   content_settings_observation_.Observe(hcsm);
+  StartRepeatedUpdates();
 }
 
 UnusedSitePermissionsService::~UnusedSitePermissionsService() = default;
@@ -167,19 +176,7 @@
 
 void UnusedSitePermissionsService::Shutdown() {
   update_timer_.Stop();
-}
-
-void UnusedSitePermissionsService::StartRepeatedUpdates() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  UpdateUnusedPermissionsAsync(base::NullCallback());
-  base::TimeDelta repeated_update_interval =
-      content_settings::features::
-          kSafetyCheckUnusedSitePermissionsRepeatedUpdateInterval.Get();
-  update_timer_.Start(
-      FROM_HERE, repeated_update_interval,
-      base::BindRepeating(
-          &UnusedSitePermissionsService::UpdateUnusedPermissionsAsync,
-          base::Unretained(this), base::NullCallback()));
+  content_settings_observation_.Reset();
 }
 
 void UnusedSitePermissionsService::RegrantPermissionsForOrigin(
@@ -254,17 +251,6 @@
   }
 }
 
-void UnusedSitePermissionsService::UpdateUnusedPermissionsAsync(
-    const base::RepeatingClosure& callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::TaskPriority::BEST_EFFORT},
-      base::BindOnce(&GetUnusedPermissionsMap, clock_, hcsm_),
-      base::BindOnce(
-          &UnusedSitePermissionsService::OnUnusedPermissionsMapRetrieved,
-          AsWeakPtr(), callback));
-}
-
 void UnusedSitePermissionsService::IgnoreOriginForAutoRevocation(
     const url::Origin& origin) {
   auto* registry = content_settings::ContentSettingsRegistry::GetInstance();
@@ -310,17 +296,6 @@
   }
 }
 
-void UnusedSitePermissionsService::OnUnusedPermissionsMapRetrieved(
-    const base::RepeatingClosure& callback,
-    UnusedPermissionMap map) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  recently_unused_permissions_ = map;
-  RevokeUnusedPermissions();
-  if (callback) {
-    callback.Run();
-  }
-}
-
 void UnusedSitePermissionsService::DeletePatternFromRevokedPermissionList(
     const ContentSettingsPattern& primary_pattern,
     const ContentSettingsPattern& secondary_pattern) {
@@ -329,6 +304,71 @@
       ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, {});
 }
 
+std::unique_ptr<UnusedSitePermissionsService::Result>
+UnusedSitePermissionsService::UpdateOnBackgroundThread() {
+  UnusedSitePermissionsService::UnusedPermissionMap recently_unused;
+  base::Time threshold =
+      clock_->Now() - content_settings::GetCoarseVisitedTimePrecision();
+  auto* registry = content_settings::ContentSettingsRegistry::GetInstance();
+  for (const content_settings::ContentSettingsInfo* info : *registry) {
+    ContentSettingsType type = info->website_settings_info()->type();
+    if (!content_settings::CanTrackLastVisit(type)) {
+      continue;
+    }
+    ContentSettingsForOneType settings = hcsm_->GetSettingsForOneType(type);
+    for (const auto& setting : settings) {
+      // Skip wildcard patterns that don't belong to a single origin. These
+      // shouldn't track visit timestamps.
+      if (!setting.primary_pattern.MatchesSingleOrigin()) {
+        continue;
+      }
+      if (setting.metadata.last_visited() != base::Time() &&
+          setting.metadata.last_visited() < threshold) {
+        GURL url = GURL(setting.primary_pattern.ToString());
+        // Converting URL to a origin is normally an anti-pattern but here it is
+        // ok since the URL belongs to a single origin. Therefore, it has a
+        // fully defined URL+scheme+port which makes converting URL to origin
+        // successful.
+        url::Origin origin = url::Origin::Create(url);
+        recently_unused[origin.Serialize()].push_back(
+            {type, std::move(setting)});
+      }
+    }
+  }
+
+  recently_unused_permissions_ = recently_unused;
+  RevokeUnusedPermissions();
+
+  return GetRevokedPermissions();
+}
+
+std::unique_ptr<UnusedSitePermissionsService::Result>
+UnusedSitePermissionsService::GetRevokedPermissions() {
+  ContentSettingsForOneType settings = hcsm_->GetSettingsForOneType(
+      ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS);
+  auto result = std::make_unique<
+      UnusedSitePermissionsService::UnusedSitePermissionsResult>();
+
+  for (const auto& revoked_permissions : settings) {
+    ContentSettingsPattern origin = revoked_permissions.primary_pattern;
+    const base::Value& stored_value = revoked_permissions.setting_value;
+    DCHECK(stored_value.is_dict());
+
+    const base::Value::List* type_list =
+        stored_value.GetDict().FindList(permissions::kRevokedKey);
+    CHECK(type_list);
+    std::set<ContentSettingsType> permission_types;
+    for (base::Value& type : type_list->Clone()) {
+      permission_types.insert(static_cast<ContentSettingsType>(type.GetInt()));
+    }
+
+    base::Time expiration = revoked_permissions.metadata.expiration();
+
+    result->AddRevokedPermission(origin, permission_types, expiration);
+  }
+  return result;
+}
+
 void UnusedSitePermissionsService::RevokeUnusedPermissions() {
   if (!base::FeatureList::IsEnabled(
           content_settings::features::kSafetyCheckUnusedSitePermissions)) {
@@ -462,13 +502,6 @@
       constraint.has_value() ? constraint.value() : default_constraint);
 }
 
-void UnusedSitePermissionsService::UpdateUnusedPermissionsForTesting() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  base::RunLoop loop;
-  UpdateUnusedPermissionsAsync(loop.QuitClosure());
-  loop.Run();
-}
-
 std::vector<UnusedSitePermissionsService::ContentSettingEntry>
 UnusedSitePermissionsService::GetTrackedUnusedPermissionsForTesting() {
   std::vector<ContentSettingEntry> result;
@@ -483,3 +516,7 @@
 void UnusedSitePermissionsService::SetClockForTesting(base::Clock* clock) {
   clock_ = clock;
 }
+
+base::WeakPtr<SafetyHubService> UnusedSitePermissionsService::GetAsWeakRef() {
+  return weak_factory_.GetWeakPtr();
+}
diff --git a/chrome/browser/ui/safety_hub/unused_site_permissions_service.h b/chrome/browser/ui/safety_hub/unused_site_permissions_service.h
index 50356c2f..7304368 100644
--- a/chrome/browser/ui/safety_hub/unused_site_permissions_service.h
+++ b/chrome/browser/ui/safety_hub/unused_site_permissions_service.h
@@ -7,6 +7,7 @@
 
 #include <list>
 #include <map>
+
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
@@ -15,6 +16,7 @@
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "chrome/browser/ui/safety_hub/safety_hub_service.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
@@ -33,13 +35,50 @@
 class Page;
 }  // namespace content
 
-// This task keeps track of unused permissions, updates their last_visit date
+// This class keeps track of unused permissions, updates their last_visit date
 // on navigations and clears them periodically.
-class UnusedSitePermissionsService
-    : public KeyedService,
-      public base::SupportsWeakPtr<UnusedSitePermissionsService>,
-      public content_settings::Observer {
+class UnusedSitePermissionsService : public SafetyHubService,
+                                     public content_settings::Observer {
  public:
+  struct RevokedPermission {
+   public:
+    RevokedPermission(ContentSettingsPattern origin,
+                      std::set<ContentSettingsType> permission_types,
+                      base::Time expiration);
+
+    RevokedPermission(const RevokedPermission&);
+    RevokedPermission& operator=(const RevokedPermission&) = delete;
+
+    ~RevokedPermission();
+
+    ContentSettingsPattern origin;
+    std::set<ContentSettingsType> permission_types;
+    base::Time expiration;
+  };
+
+  // The result of the periodic update of unused site permissions contains
+  // the permissions that have been revoked. These revoked permissions will be
+  // stored until the clean-up threshold has been reached.
+  class UnusedSitePermissionsResult : public SafetyHubService::Result {
+   public:
+    UnusedSitePermissionsResult();
+
+    UnusedSitePermissionsResult(const UnusedSitePermissionsResult&) = delete;
+    UnusedSitePermissionsResult& operator=(const UnusedSitePermissionsResult&) =
+        delete;
+
+    ~UnusedSitePermissionsResult() override;
+
+    void AddRevokedPermission(ContentSettingsPattern origin,
+                              std::set<ContentSettingsType> permission_types,
+                              base::Time expiration);
+
+    std::list<RevokedPermission> GetRevokedPermissions();
+
+   private:
+    std::list<RevokedPermission> revoked_permissions_;
+  };
+
   struct ContentSettingEntry {
     ContentSettingsType type;
     ContentSettingPatternSource source;
@@ -87,10 +126,6 @@
   // permissions for that site should not be auto-revoked again by the service.
   void IgnoreOriginForAutoRevocation(const url::Origin& origin);
 
-  // Triggers an update of the unused permission map. Automatically registers
-  // a delayed task for another update after 24h.
-  void StartRepeatedUpdates();
-
   // Re-grants permissions that are auto-revoked ones and removes the origin
   // from revoked permissions list.
   void RegrantPermissionsForOrigin(const url::Origin& origin);
@@ -114,28 +149,22 @@
           constraint,
       const url::Origin origin);
 
+  // Returns the list of all permissions that have been revoked.
+  std::unique_ptr<UnusedSitePermissionsService::Result> GetRevokedPermissions();
+
   // Test support:
   void SetClockForTesting(base::Clock* clock);
   std::vector<ContentSettingEntry> GetTrackedUnusedPermissionsForTesting();
-  void UpdateUnusedPermissionsForTesting();
 
   using UnusedPermissionMap =
       std::map<std::string, std::list<ContentSettingEntry>>;
 
- private:
-  FRIEND_TEST_ALL_PREFIXES(UnusedSitePermissionsServiceTest,
-                           UpdateUnusedPermissionsAsync);
+  base::WeakPtr<SafetyHubService> GetAsWeakRef() override;
 
+ private:
   // Called by TabHelper when a URL was visited.
   void OnPageVisited(const url::Origin& origin);
 
-  // Called on UI thread
-  void UpdateUnusedPermissionsAsync(const base::RepeatingClosure& callback);
-
-  // Called on UI thread.
-  void OnUnusedPermissionsMapRetrieved(const base::RepeatingClosure& callback,
-                                       UnusedPermissionMap map);
-
   // Removes a pattern from the list of revoked permissions so that the entry is
   // no longer shown to the user. Does not affect permissions themselves.
   void DeletePatternFromRevokedPermissionList(
@@ -154,6 +183,17 @@
       const ContentSettingsPattern& primary_pattern,
       const ContentSettingsPattern& secondary_pattern);
 
+  // Safety Hub overrides
+
+  // Returns the interval at which the repeated updates will be run.
+  base::TimeDelta GetRepeatedUpdateInterval() override;
+
+  // This function is called periodically (every 24h and on browser start), and
+  // computes the permissions that need to be revoked. It returns an
+  // UnusedSitePermissionsResult with all permissions that have been revoked.
+  std::unique_ptr<UnusedSitePermissionsService::Result>
+  UpdateOnBackgroundThread() override;
+
   // Set of permissions that haven't been used for at least a week.
   UnusedPermissionMap recently_unused_permissions_;
   // Repeating timer that updates the recently_unused_permissions_ map.
@@ -166,6 +206,8 @@
       content_settings_observation_{this};
 
   raw_ptr<base::Clock> clock_;
+
+  base::WeakPtrFactory<UnusedSitePermissionsService> weak_factory_{this};
 };
 
 #endif  // CHROME_BROWSER_UI_SAFETY_HUB_UNUSED_SITE_PERMISSIONS_SERVICE_H_
diff --git a/chrome/browser/ui/safety_hub/unused_site_permissions_service_browsertest.cc b/chrome/browser/ui/safety_hub/unused_site_permissions_service_browsertest.cc
index 84c7036..26a9e5b 100644
--- a/chrome/browser/ui/safety_hub/unused_site_permissions_service_browsertest.cc
+++ b/chrome/browser/ui/safety_hub/unused_site_permissions_service_browsertest.cc
@@ -68,7 +68,7 @@
   map->SetContentSettingDefaultScope(url, url, ContentSettingsType::GEOLOCATION,
                                      CONTENT_SETTING_ALLOW, constraints);
   clock.SetNow(now);
-  service->UpdateUnusedPermissionsForTesting();
+  service->UpdateOnBackgroundThreadForTesting();
   ASSERT_EQ(service->GetTrackedUnusedPermissionsForTesting().size(), 1u);
 
   // Check that the timestamp is initially in the past.
@@ -89,6 +89,7 @@
   EXPECT_LE(info.metadata.last_visited(), now);
 
   map->SetClockForTesting(base::DefaultClock::GetInstance());
+  service->SetClockForTesting(base::DefaultClock::GetInstance());
 }
 
 // Test that navigations work fine in incognito mode.
@@ -123,7 +124,7 @@
   clock.SetNow(now);
 
   // Check if the content setting is still ALLOW, before auto-revocation.
-  service->UpdateUnusedPermissionsForTesting();
+  service->UpdateOnBackgroundThreadForTesting();
   ASSERT_EQ(service->GetTrackedUnusedPermissionsForTesting().size(), 1u);
   ASSERT_EQ(GetRevokedUnusedPermissions(map).size(), 0u);
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
@@ -133,11 +134,14 @@
   clock.Advance(base::Days(40));
 
   // Check if the content setting turn to ASK, when auto-revocation happens.
-  service->UpdateUnusedPermissionsForTesting();
+  service->UpdateOnBackgroundThreadForTesting();
   ASSERT_EQ(service->GetTrackedUnusedPermissionsForTesting().size(), 0u);
   ASSERT_EQ(GetRevokedUnusedPermissions(map).size(), 1u);
   EXPECT_EQ(CONTENT_SETTING_ASK,
             map->GetContentSetting(url, url, ContentSettingsType::GEOLOCATION));
+
+  map->SetClockForTesting(base::DefaultClock::GetInstance());
+  service->SetClockForTesting(base::DefaultClock::GetInstance());
 }
 
 // Test that revocation happens correctly for all content setting types.
@@ -181,7 +185,7 @@
 
   // Travel through time for 70 days to make permissions be revoked.
   clock.Advance(base::Days(70));
-  service->UpdateUnusedPermissionsForTesting();
+  service->UpdateOnBackgroundThreadForTesting();
   ASSERT_EQ(GetRevokedUnusedPermissions(map).size(), 1u);
 
   // Navigate to content settings page.
diff --git a/chrome/browser/ui/safety_hub/unused_site_permissions_service_factory.cc b/chrome/browser/ui/safety_hub/unused_site_permissions_service_factory.cc
index 6de162a..cebead8 100644
--- a/chrome/browser/ui/safety_hub/unused_site_permissions_service_factory.cc
+++ b/chrome/browser/ui/safety_hub/unused_site_permissions_service_factory.cc
@@ -42,6 +42,5 @@
     content::BrowserContext* context) const {
   auto* service = new UnusedSitePermissionsService(
       HostContentSettingsMapFactory::GetForProfile(context));
-  service->StartRepeatedUpdates();
   return service;
 }
diff --git a/chrome/browser/ui/safety_hub/unused_site_permissions_service_unittest.cc b/chrome/browser/ui/safety_hub/unused_site_permissions_service_unittest.cc
index 988411b..eb8afd0b 100644
--- a/chrome/browser/ui/safety_hub/unused_site_permissions_service_unittest.cc
+++ b/chrome/browser/ui/safety_hub/unused_site_permissions_service_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
 #include "base/time/clock.h"
+#include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -49,8 +50,11 @@
   }
 
   void TearDown() override {
+    service_->SetClockForTesting(base::DefaultClock::GetInstance());
+    hcsm_->SetClockForTesting(base::DefaultClock::GetInstance());
     service_->Shutdown();
     hcsm_->ShutdownOnUIThread();
+    base::RunLoop().RunUntilIdle();
     ChromeRenderViewHostTestHarness::TearDown();
   }
 
@@ -132,7 +136,7 @@
       url2, url2, type1, ContentSetting::CONTENT_SETTING_ALLOW, constraint);
   hcsm()->SetContentSettingDefaultScope(
       url2, url2, type2, ContentSetting::CONTENT_SETTING_ALLOW, constraint);
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(service()->GetTrackedUnusedPermissionsForTesting().size(), 0u);
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 0u);
 
@@ -141,7 +145,7 @@
   base::Time future = clock()->Now();
 
   // The old settings should now be tracked as unused.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(service()->GetTrackedUnusedPermissionsForTesting().size(), 3u);
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 0u);
 
@@ -163,7 +167,7 @@
   clock()->Advance(base::Days(50));
 
   // Unused permissions should be auto revoked.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   // url2 should be on tracked permissions list.
   EXPECT_EQ(service()->GetTrackedUnusedPermissionsForTesting().size(), 2u);
   std::string url2_str =
@@ -197,7 +201,7 @@
       url2, url2, type, ContentSetting::CONTENT_SETTING_ALLOW, constraint);
   hcsm()->SetContentSettingDefaultScope(
       url2, url3, type, ContentSetting::CONTENT_SETTING_ALLOW, constraint);
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(service()->GetTrackedUnusedPermissionsForTesting().size(), 0u);
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 0u);
 
@@ -205,7 +209,7 @@
   clock()->Advance(base::Days(20));
 
   // Only `url1` should be tracked because it is the only single origin url.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(service()->GetTrackedUnusedPermissionsForTesting().size(), 1u);
   auto tracked_origin = service()->GetTrackedUnusedPermissionsForTesting()[0];
   EXPECT_EQ(GURL(tracked_origin.source.primary_pattern.ToString()), url1);
@@ -232,7 +236,7 @@
   // list as it is denied 20 days before. The permission is not suitable for
   // revocation and this test verifies that RevokeUnusedPermissions() does not
   // enter infinite loop in such case.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   auto unused_permissions = service()->GetTrackedUnusedPermissionsForTesting();
   ASSERT_EQ(unused_permissions.size(), 1u);
   EXPECT_EQ(unused_permissions[0].type, ContentSettingsType::GEOLOCATION);
@@ -268,12 +272,12 @@
         ContentSetting::CONTENT_SETTING_ALLOW, constraint);
   }
 
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 0u);
 
   // Travel through time for 70 days so that permissions are revoked.
   clock()->Advance(base::Days(70));
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
 
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 4u);
   for (auto unused_permission : GetRevokedUnusedPermissions(hcsm())) {
@@ -309,7 +313,7 @@
   // GEOLOCATION permission should be on the tracked unused site permissions
   // list as it is granted 20 days before. MEDIASTREAM_CAMERA permission should
   // not be tracked as it is just granted.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(service()->GetTrackedUnusedPermissionsForTesting().size(), 1u);
   EXPECT_EQ(service()->GetTrackedUnusedPermissionsForTesting()[0].type,
             ContentSettingsType::GEOLOCATION);
@@ -320,7 +324,7 @@
   // GEOLOCATION permission should be on the revoked permissions list as it is
   // granted 70 days before. MEDIASTREAM_CAMERA permission should be on the
   // recently unused permissions list as it is granted 50 days before.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedPermissionsForOneOrigin(hcsm(), url).size(), 1u);
   EXPECT_EQ(GetRevokedPermissionsForOneOrigin(hcsm(), url)[0].GetInt(),
             static_cast<int32_t>(ContentSettingsType::GEOLOCATION));
@@ -350,7 +354,7 @@
 
   // Both GEOLOCATION and MEDIASTREAM_CAMERA permissions should be on the
   // revoked permissions list as they are granted more than 60 days before.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedPermissionsForOneOrigin(hcsm(), url).size(), 2u);
   EXPECT_EQ(GetRevokedPermissionsForOneOrigin(hcsm(), url)[0].GetInt(),
             static_cast<int32_t>(ContentSettingsType::GEOLOCATION));
@@ -362,7 +366,7 @@
 
   // No permission should be on the revoked permissions list as they are revoked
   // more than 30 days before.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedPermissionsForOneOrigin(hcsm(), url).size(), 0u);
 }
 
@@ -431,7 +435,7 @@
 
   // Travel 70 days through time so that the granted permission is revoked.
   clock()->Advance(base::Days(70));
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 1u);
 
   // After regranting permissions they are not revoked again even after >60 days
@@ -440,7 +444,7 @@
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 0u);
 
   clock()->Advance(base::Days(70));
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 0u);
 }
 
@@ -460,7 +464,7 @@
 
   // Travel 70 days through time so that the granted permission is revoked.
   clock()->Advance(base::Days(70));
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 1u);
   const ContentSettingPatternSource revoked_permission =
       GetRevokedUnusedPermissions(hcsm())[0];
@@ -477,14 +481,14 @@
 
   // Revoked permission is cleaned up after >30 days.
   clock()->Advance(base::Days(40));
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 0u);
 
   // If that permission is granted again, it will still be autorevoked.
   hcsm()->SetContentSettingDefaultScope(
       url1, url1, type, ContentSetting::CONTENT_SETTING_ALLOW, constraint);
   clock()->Advance(base::Days(70));
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 1u);
 }
 
@@ -513,7 +517,7 @@
   // GEOLOCATION permission should be on the revoked permissions list, but
   // NOTIFICATION permissions should not be as notification permissions are out
   // of scope.
-  service()->UpdateUnusedPermissionsForTesting();
+  service()->UpdateOnBackgroundThreadForTesting();
   EXPECT_EQ(GetRevokedPermissionsForOneOrigin(hcsm(), url).size(), 1u);
   EXPECT_EQ(GetRevokedPermissionsForOneOrigin(hcsm(), url)[0].GetInt(),
             static_cast<int32_t>(ContentSettingsType::GEOLOCATION));
@@ -636,19 +640,3 @@
       ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS);
   EXPECT_EQ(1U, revoked_permissions_list.size());
 }
-
-TEST_F(UnusedSitePermissionsServiceTest, UpdateUnusedPermissionsAsync) {
-  EXPECT_EQ(callback_count(), 0);
-  // The repeating callback should be called every time after
-  // UpdateUnusedPermissionsAsync has finished running.
-  base::RunLoop loop;
-  int num_calls = 2;
-  base::RepeatingCallback callback = base::BindRepeating(
-      &UnusedSitePermissionsServiceTest::OnUpdateAsyncFinished,
-      base::Unretained(this), num_calls, loop.QuitClosure());
-  for (int i = 0; i < num_calls; i++) {
-    service()->UpdateUnusedPermissionsAsync(callback);
-  }
-  loop.Run();
-  EXPECT_EQ(callback_count(), 2);
-}
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc
index 6b193bd..e9463c0 100644
--- a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc
@@ -15,6 +15,7 @@
 #include "components/autofill/core/browser/data_model/autofill_offer_data.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
+#include "components/commerce/core/commerce_feature_list.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
@@ -73,11 +74,12 @@
 }
 
 void OfferNotificationBubbleViews::AddedToWidget() {
-  GetBubbleFrameView()->SetTitleView(CreateTitleView(
-      GetWindowTitle(), TitleWithIconAndSeparatorView::Icon::GOOGLE_G));
-
-  // Set the header image for free listing coupon notification bubble.
   if (controller_->GetOffer()->IsFreeListingCouponOffer()) {
+    GetBubbleFrameView()->SetTitleView(
+        std::make_unique<TitleWithIconAndSeparatorView>(
+            GetWindowTitle(), TitleWithIconAndSeparatorView::Icon::GOOGLE_G));
+
+    // Set the header image.
     ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
     auto* autofill_offers_banner =
         bundle.GetImageSkiaNamed(IDR_AUTOFILL_OFFERS);
@@ -86,6 +88,9 @@
         base::BindRepeating(&views::BubbleDialogDelegate::GetBackgroundColor,
                             base::Unretained(this)));
     GetBubbleFrameView()->SetHeaderView(std::move(image_view));
+  } else {
+    GetBubbleFrameView()->SetTitleView(CreateTitleView(
+        GetWindowTitle(), TitleWithIconAndSeparatorView::Icon::GOOGLE_G));
   }
 }
 
@@ -103,8 +108,9 @@
 
 void OfferNotificationBubbleViews::OnWidgetDestroying(views::Widget* widget) {
   LocationBarBubbleDelegateView::OnWidgetDestroying(widget);
-  if (!widget->IsClosed())
+  if (!widget->IsClosed()) {
     return;
+  }
   DCHECK_NE(widget->closed_reason(),
             views::Widget::ClosedReason::kCancelButtonClicked);
 }
@@ -150,13 +156,35 @@
               base::Unretained(this)),
           base::ASCIIToUTF16(offer->GetPromoCode())));
 
+  std::u16string promo_code_value_prop_string;
+
   if (!offer->GetDisplayStrings().value_prop_text.empty()) {
+    promo_code_value_prop_string =
+        base::ASCIIToUTF16(offer->GetDisplayStrings().value_prop_text);
+  }
+
+  if (base::FeatureList::IsEnabled(commerce::kShowDiscountOnNavigation)) {
+    // TODO(b/296338434): Update the format of the date.
+    auto expiration_date_text = l10n_util::GetStringFUTF16(
+        IDS_DISCOUNT_EXPIRATION_DATE,
+        base::ASCIIToUTF16(TimeFormatHTTP(offer->GetExpiry())));
+    if (promo_code_value_prop_string.empty()) {
+      promo_code_value_prop_string = expiration_date_text;
+    } else {
+      promo_code_value_prop_string = l10n_util::GetStringFUTF16(
+          IDS_TWO_STRINGS_CONNECTOR, promo_code_value_prop_string,
+          expiration_date_text);
+    }
+  }
+
+  if (!promo_code_value_prop_string.empty()) {
     auto* promo_code_value_prop = AddChildView(std::make_unique<views::Label>(
-        base::ASCIIToUTF16(offer->GetDisplayStrings().value_prop_text),
-        views::style::CONTEXT_DIALOG_BODY_TEXT, views::style::STYLE_SECONDARY));
+        promo_code_value_prop_string, views::style::CONTEXT_DIALOG_BODY_TEXT,
+        views::style::STYLE_SECONDARY));
     promo_code_value_prop->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     promo_code_value_prop->SetMultiLine(true);
   }
+
   UpdateButtonTooltipsAndAccessibleNames();
 }
 
@@ -230,8 +258,9 @@
 }
 
 void OfferNotificationBubbleViews::UpdateButtonTooltipsAndAccessibleNames() {
-  if (!promo_code_label_button_)
+  if (!promo_code_label_button_) {
     return;
+  }
 
   std::u16string tooltip = controller_->GetPromoCodeButtonTooltip();
   promo_code_label_button_->SetTooltipText(tooltip);
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc
index d550afe4..2d86109 100644
--- a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_interactive_uitest.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser.h"
@@ -24,6 +25,7 @@
 #include "components/autofill/core/browser/test_autofill_clock.h"
 #include "components/autofill/core/browser/ui/payments/payments_bubble_closed_reasons.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
+#include "components/commerce/core/commerce_feature_list.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,8 +40,17 @@
 
 namespace autofill {
 
-typedef std::tuple<AutofillOfferData::OfferType>
-    OfferNotificationBubbleViewsInteractiveUiTestData;
+struct OfferNotificationBubbleViewsInteractiveUiTestData {
+  std::string name;
+  AutofillOfferData::OfferType offer_type;
+  absl::optional<std::vector<base::test::FeatureRefAndParams>> enabled_features;
+};
+
+std::string GetTestName(
+    const ::testing::TestParamInfo<
+        OfferNotificationBubbleViewsInteractiveUiTestData>& info) {
+  return info.param.name;
+}
 
 class OfferNotificationBubbleViewsInteractiveUiTest
     : public OfferNotificationBubbleViewsTestBase,
@@ -47,7 +58,13 @@
           OfferNotificationBubbleViewsInteractiveUiTestData> {
  public:
   OfferNotificationBubbleViewsInteractiveUiTest()
-      : test_offer_type_(std::get<0>(GetParam())) {}
+      : test_offer_type_(GetParam().offer_type) {
+    if (GetParam().enabled_features.has_value()) {
+      feature_list_.InitWithFeaturesAndParameters(
+          GetParam().enabled_features.value(),
+          /*disabled_features=*/{});
+    }
+  }
 
   ~OfferNotificationBubbleViewsInteractiveUiTest() override = default;
   OfferNotificationBubbleViewsInteractiveUiTest(
@@ -149,22 +166,35 @@
 
   TestAutofillClock test_clock_;
   const AutofillOfferData::OfferType test_offer_type_;
+  base::test::ScopedFeatureList feature_list_;
 };
 
 // TODO(https://crbug.com/1334806): Split parameterized tests that are
 // applicable for only one offer type.
 INSTANTIATE_TEST_SUITE_P(
-    GpayCardLinked,
+    GPayCardLinked,
     OfferNotificationBubbleViewsInteractiveUiTest,
-    testing::Values(AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER));
+    testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{
+        "GPayCardLinked",
+        AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER}));
 INSTANTIATE_TEST_SUITE_P(
     FreeListingCoupon,
     OfferNotificationBubbleViewsInteractiveUiTest,
-    testing::Values(AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER));
+    testing::Values(
+        OfferNotificationBubbleViewsInteractiveUiTestData{
+            "FreeListingCoupon_default",
+            AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER},
+        OfferNotificationBubbleViewsInteractiveUiTestData{
+            "FreeListingCoupon_on_navigation",
+            AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER,
+            absl::make_optional<std::vector<base::test::FeatureRefAndParams>>(
+                {{commerce::kShowDiscountOnNavigation, {}}})}),
+    GetTestName);
 INSTANTIATE_TEST_SUITE_P(
     GPayPromoCode,
     OfferNotificationBubbleViewsInteractiveUiTest,
-    testing::Values(AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER));
+    testing::Values(OfferNotificationBubbleViewsInteractiveUiTestData{
+        "GPayPromoCode", AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER}));
 
 // TODO(https://crbug.com/1289161): Flaky failures.
 #if BUILDFLAG(IS_LINUX)
@@ -321,8 +351,10 @@
                        DismissBubble) {
   // Applies to card-linked offers only, as promo code offers do not have an OK
   // button.
-  if (test_offer_type_ != AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER)
+  if (test_offer_type_ !=
+      AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER) {
     return;
+  }
 
   ShowBubbleForOfferAndVerify();
 
@@ -364,8 +396,10 @@
                        Logging_Acknowledged) {
   // Applies to card-linked offers only, as promo code offers do not have an OK
   // button.
-  if (test_offer_type_ != AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER)
+  if (test_offer_type_ !=
+      AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER) {
     return;
+  }
 
   base::HistogramTester histogram_tester;
   ShowBubbleForOfferAndVerify();
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_pixel_browsertest.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_pixel_browsertest.cc
new file mode 100644
index 0000000..26183aafa
--- /dev/null
+++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_pixel_browsertest.cc
@@ -0,0 +1,133 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
+#include "chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.h"
+#include "chrome/browser/ui/test/test_browser_dialog.h"
+#include "chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
+#include "components/commerce/core/commerce_feature_list.h"
+#include "content/public/test/browser_test.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/views/widget/any_widget_observer.h"
+
+#include "chrome/test/base/test_browser_window.h"
+namespace autofill {
+
+namespace {
+const char kTestURL[] = "https://www.example.com/first/";
+const char kTestPromoCode[] = "FREEFALL1234";
+
+AutofillOfferData CreateTestFreeListingCouponOffer(
+    const std::vector<GURL>& merchant_origins,
+    const std::string& promo_code) {
+  int64_t offer_id = 2468;
+  base::Time expiry = base::Time::Now() + base::Days(2);
+  autofill::DisplayStrings display_strings;
+  display_strings.value_prop_text = "5% off on shoes";
+  display_strings.see_details_text = "See details";
+  display_strings.usage_instructions_text =
+      "Click the promo code field at checkout to autofill it.";
+  return autofill::AutofillOfferData::FreeListingCouponOffer(
+      offer_id, expiry, merchant_origins, /*offer_details_url=*/GURL(),
+      display_strings, promo_code);
+}
+}  // namespace
+
+struct OfferNotificationBubbleViewPixelTestConfig {
+  std::string name;
+  absl::optional<std::vector<base::test::FeatureRefAndParams>> enabled_features;
+};
+
+std::string GetTestName(
+    const ::testing::TestParamInfo<OfferNotificationBubbleViewPixelTestConfig>&
+        info) {
+  return info.param.name;
+}
+
+// Pixel test for OfferNotificationBubbleView. Pixel tests run in
+// DialogBrowserTest::VerifyUi().
+class OfferNotificationBubbleViewPixelBrowserTest
+    : public DialogBrowserTest,
+      public testing::WithParamInterface<
+          OfferNotificationBubbleViewPixelTestConfig> {
+ public:
+  OfferNotificationBubbleViewPixelBrowserTest() {
+    if (GetParam().enabled_features.has_value()) {
+      feature_list_.InitWithFeaturesAndParameters(
+          GetParam().enabled_features.value(),
+          /*disabled_features=*/{});
+    }
+  }
+  // DialogBrowserTest:
+  void ShowUi(const std::string& name) override {
+    ui::ScopedAnimationDurationScaleMode disable_animation(
+        ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+    AutofillOfferData offer = CreateTestFreeListingCouponOffer(
+        /*merchant_origins=*/{GURL(kTestURL).DeprecatedGetOriginAsURL()},
+        kTestPromoCode);
+    auto* autofill_client =
+        ChromeAutofillClient::FromWebContentsForTesting(GetWebContents());
+
+    auto offer_notification_bubble_view_waiter = views::NamedWidgetShownWaiter(
+        views::test::AnyWidgetTestPasskey{},
+        OfferNotificationBubbleViews::kViewClassName);
+
+    autofill_client->UpdateOfferNotification(
+        &offer, /*notification_has_been_shown=*/true,
+        /*expand_notification_icon=*/false);
+    OfferNotificationBubbleControllerImpl* controller = GetController();
+    EXPECT_TRUE(controller);
+    // Ensure the window is active before reshowing the bubble.
+    static_cast<TestBrowserWindow*>(browser()->window())->set_is_active(true);
+    controller->ReshowBubble();
+    EXPECT_TRUE(offer_notification_bubble_view_waiter.WaitIfNeededAndGet());
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+
+  content::WebContents* GetWebContents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  OfferNotificationBubbleViews* GetOfferNotificationBubbleViews() {
+    OfferNotificationBubbleControllerImpl* controller = GetController();
+    if (!controller) {
+      return nullptr;
+    }
+    return static_cast<OfferNotificationBubbleViews*>(
+        controller->GetOfferNotificationBubbleView());
+  }
+
+  OfferNotificationBubbleControllerImpl* GetController() {
+    return static_cast<OfferNotificationBubbleControllerImpl*>(
+        OfferNotificationBubbleController::Get(GetWebContents()));
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    OfferNotificationBubbleViewPixelBrowserTest,
+    testing::Values(
+        OfferNotificationBubbleViewPixelTestConfig{"FreeListingOffer_default"},
+        OfferNotificationBubbleViewPixelTestConfig{
+            "FreeListingOffer_on_navigation",
+            absl::make_optional<std::vector<base::test::FeatureRefAndParams>>(
+                {{commerce::kShowDiscountOnNavigation, {}}})}),
+    GetTestName);
+
+// TODO(crbug.com/1473417): Disabled because this is flaky on the bots, but not
+// locally. Based on the logs, somehow the browser window becomes inactive
+// during the test which causes the bubble not to show.
+IN_PROC_BROWSER_TEST_P(OfferNotificationBubbleViewPixelBrowserTest,
+                       DISABLED_InvokeUi_show_notification_bubble) {
+  ShowAndVerifyUi();
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index d849c27..f2d4713 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1041,10 +1041,10 @@
 
   // Dragging the center of the first tab to the center of the third tab will
   // result in the tabs joining the end of Tab Group 4.
-  const gfx::Point left_center_third_tab =
-      test::GetLeftCenterInScreenCoordinates(tab_strip->tab_at(2));
+  const gfx::Point center_third_tab =
+      GetCenterInScreenCoordinates(tab_strip->tab_at(2));
   ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(0))));
-  ASSERT_TRUE(DragInputTo(left_center_third_tab));
+  ASSERT_TRUE(DragInputTo(center_third_tab));
   ASSERT_TRUE(ReleaseInput());
   StopAnimating(tab_strip);
 
diff --git a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
index 5aea1af..61921105 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -172,7 +173,13 @@
 
 // Test that the models decide to show the "Manage devices" button when a phone
 // is listed.
-// TODO(crbug.com/1474278): Re-enable this test
-IN_PROC_BROWSER_TEST_F(AuthenticatorDialogViewTest, InvokeUi_manage_devices) {
+// TODO(crbug.com/1474278): Flaky on Mac, Re-enable this test
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_InvokeUi_manage_devices DISABLED_InvokeUi_manage_devices
+#else
+#define MAYBE_InvokeUi_manage_devices InvokeUi_manage_devices
+#endif
+IN_PROC_BROWSER_TEST_F(AuthenticatorDialogViewTest,
+                       MAYBE_InvokeUi_manage_devices) {
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/ui/web_applications/web_app_metrics_factory.cc b/chrome/browser/ui/web_applications/web_app_metrics_factory.cc
index 20189bd8..5a002712 100644
--- a/chrome/browser/ui/web_applications/web_app_metrics_factory.cc
+++ b/chrome/browser/ui/web_applications/web_app_metrics_factory.cc
@@ -36,10 +36,11 @@
 
 WebAppMetricsFactory::~WebAppMetricsFactory() = default;
 
-KeyedService* WebAppMetricsFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+WebAppMetricsFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
-  return new WebAppMetrics(profile);
+  return std::make_unique<WebAppMetrics>(profile);
 }
 
 content::BrowserContext* WebAppMetricsFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/ui/web_applications/web_app_metrics_factory.h b/chrome/browser/ui/web_applications/web_app_metrics_factory.h
index 25a8dcd..08877cf 100644
--- a/chrome/browser/ui/web_applications/web_app_metrics_factory.h
+++ b/chrome/browser/ui/web_applications/web_app_metrics_factory.h
@@ -36,7 +36,7 @@
   ~WebAppMetricsFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc
index 7871fee..d45bb726 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc
@@ -411,8 +411,7 @@
 
 // Check QuickOffice was observed by the dialog as it should always be shown.
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-  ASSERT_TRUE(file_manager::file_tasks::IsExtensionInstalled(
-      profile(), extension_misc::kQuickOfficeComponentExtensionId));
+  ASSERT_TRUE(file_manager::file_tasks::IsQuickOfficeInstalled(profile()));
   ASSERT_GE(PositionInList(observed_app_ids,
                            extension_misc::kQuickOfficeComponentExtensionId),
             0);
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
index fe5d4d1..1f8bc78b 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
@@ -123,8 +123,8 @@
 
   if (!profile_) {
     LOG(ERROR) << "No profile";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kOtherError,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kOtherError);
     return;
   }
 
@@ -132,30 +132,30 @@
       file_manager::VolumeManager::Get(profile_);
   if (!volume_manager) {
     LOG(ERROR) << "No volume manager";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kOtherError,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kOtherError);
     return;
   }
   io_task_controller_ = volume_manager->io_task_controller();
   if (!io_task_controller_) {
     LOG(ERROR) << "No task_controller";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kOtherError,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kOtherError);
     return;
   }
 
   if (!drive_integration_service_) {
     LOG(ERROR) << "No Drive integration service";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kOtherError,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kOtherError);
     return;
   }
 
   if (drive::util::GetDriveConnectionStatus(profile_) !=
       drive::util::DRIVE_CONNECTED) {
     LOG(ERROR) << "No connection to Drive";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kNoConnection,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kNoConnection);
     return;
   }
 
@@ -168,8 +168,8 @@
 
   if (!drive_integration_service_->IsMounted()) {
     LOG(ERROR) << "Google Drive is not mounted";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kFileSystemNotFound,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kFileSystemNotFound);
     return;
   }
 
@@ -181,8 +181,8 @@
   // TODO (b/243095484) Define error behavior.
   if (!destination_folder_url.is_valid()) {
     LOG(ERROR) << "Unable to generate destination folder Drive URL";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kFileSystemNotFound,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kFileSystemNotFound);
     return;
   }
 
@@ -204,9 +204,8 @@
   notification_manager_->ShowUploadProgress(progress);
 }
 
-void DriveUploadHandler::OnEndCopy(GURL hosted_url,
-                                   OfficeFilesUploadResult result,
-                                   std::string error_message) {
+void DriveUploadHandler::OnEndCopy(base::expected<GURL, std::string> hosted_url,
+                                   OfficeFilesUploadResult result_metric) {
   if (copy_ended_) {
     // Prevent loops in case Copy IO task and Drive sync fail separately.
     return;
@@ -215,9 +214,8 @@
 
   // If copy to Drive was successful and intended operation is a copy, no delete
   // is required.
-  if (result == OfficeFilesUploadResult::kSuccess &&
-      upload_type_ == UploadType::kCopy) {
-    OnEndUpload(hosted_url, result, error_message);
+  if (hosted_url.has_value() && upload_type_ == UploadType::kCopy) {
+    OnEndUpload(hosted_url, result_metric);
     return;
   }
 
@@ -228,24 +226,18 @@
       drive_integration_service_->GetRelativeDrivePath(
           observed_absolute_dest_path_, &rel_path);
   if (!destination_file_exists) {
-    OnEndUpload(hosted_url, result, error_message);
+    OnEndUpload(hosted_url, result_metric);
     return;
   }
 
-  end_upload_callback_ = base::BindOnce(&DriveUploadHandler::OnEndUpload,
-                                        weak_ptr_factory_.GetWeakPtr(),
-                                        hosted_url, result, error_message);
+  end_upload_callback_ =
+      base::BindOnce(&DriveUploadHandler::OnEndUpload,
+                     weak_ptr_factory_.GetWeakPtr(), hosted_url, result_metric);
 
-  ConvertToMoveOrUndoUpload(result);
-}
-
-void DriveUploadHandler::ConvertToMoveOrUndoUpload(
-    OfficeFilesUploadResult result) {
   std::vector<FileSystemURL> file_urls;
-
-  // If copy to Drive was successful, delete source file to convert the upload
-  // to a move to Drive.
-  if (result == OfficeFilesUploadResult::kSuccess) {
+  if (hosted_url.has_value()) {
+    // If copy to Drive was successful, delete source file to convert the upload
+    // to a move to Drive.
     file_urls.push_back(source_url_);
   } else {
     // If copy to Drive was unsuccessful, delete destination file to undo the
@@ -262,11 +254,11 @@
   observed_delete_task_id_ = io_task_controller_->Add(std::move(task));
 }
 
-void DriveUploadHandler::OnEndUpload(GURL hosted_url,
-                                     OfficeFilesUploadResult result,
-                                     std::string error_message) {
-  UMA_HISTOGRAM_ENUMERATION(kGoogleDriveUploadResultMetricName, result);
-  if (result != OfficeFilesUploadResult::kSuccess) {
+void DriveUploadHandler::OnEndUpload(
+    base::expected<GURL, std::string> hosted_url,
+    OfficeFilesUploadResult result_metric) {
+  UMA_HISTOGRAM_ENUMERATION(kGoogleDriveUploadResultMetricName, result_metric);
+  if (result_metric != OfficeFilesUploadResult::kSuccess) {
     UMA_HISTOGRAM_ENUMERATION(kGoogleDriveTaskResultMetricName,
                               OfficeTaskResult::kFailedToUpload);
   }
@@ -276,15 +268,16 @@
   scoped_suppress_drive_notifications_for_path_.reset();
   // Resolve notifications.
   if (notification_manager_) {
-    if (hosted_url.is_valid()) {
+    if (hosted_url.has_value()) {
       notification_manager_->MarkUploadComplete();
-    } else if (!error_message.empty()) {
+    } else if (const std::string& error_message = hosted_url.error();
+               !error_message.empty()) {
       LOG(ERROR) << "Cloud upload: " << error_message;
       notification_manager_->ShowUploadError(error_message);
     }
   }
   if (callback_) {
-    std::move(callback_).Run(hosted_url, upload_size_);
+    std::move(callback_).Run(hosted_url.value_or(GURL()), upload_size_);
   }
 }
 
@@ -320,8 +313,8 @@
 
         if (!drive_integration_service_) {
           LOG(ERROR) << "No Drive integration service";
-          OnEndCopy(GURL(), OfficeFilesUploadResult::kOtherError,
-                    GetGenericErrorMessage());
+          OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                    OfficeFilesUploadResult::kOtherError);
           return;
         }
 
@@ -348,11 +341,11 @@
     case file_manager::io_task::State::kCancelled:
       LOG(ERROR) << "Upload to Google Drive cancelled";
       if (upload_type_ == UploadType::kCopy) {
-        OnEndCopy(GURL(), OfficeFilesUploadResult::kCopyOperationCancelled,
-                  GetGenericErrorMessage());
+        OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                  OfficeFilesUploadResult::kCopyOperationCancelled);
       } else {
-        OnEndCopy(GURL(), OfficeFilesUploadResult::kMoveOperationCancelled,
-                  GetGenericErrorMessage());
+        OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                  OfficeFilesUploadResult::kMoveOperationCancelled);
       }
       return;
     case file_manager::io_task::State::kError:
@@ -430,7 +423,7 @@
   base::UmaHistogramExactLinear(
       copy ? kGoogleDriveCopyErrorMetricName : kGoogleDriveMoveErrorMetricName,
       -file_error, -base::File::FILE_ERROR_MAX);
-  OnEndCopy(GURL(), upload_result, error_message);
+  OnEndCopy(base::unexpected(error_message), upload_result);
 }
 
 void DriveUploadHandler::OnUnmounted() {}
@@ -477,13 +470,13 @@
         return;
       case drivefs::mojom::ItemEvent::State::kFailed:
         LOG(ERROR) << "Drive sync error";
-        OnEndCopy(GURL(), OfficeFilesUploadResult::kCloudError,
-                  GetGenericErrorMessage());
+        OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                  OfficeFilesUploadResult::kCloudError);
         return;
       default:
         LOG(ERROR) << "Drive sync error + invalid sync state";
-        OnEndCopy(GURL(), OfficeFilesUploadResult::kCloudError,
-                  GetGenericErrorMessage());
+        OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                  OfficeFilesUploadResult::kCloudError);
         return;
     }
   }
@@ -499,8 +492,7 @@
     case drivefs::mojom::DriveError::Type::kCantUploadStorageFullOrganization:
     case drivefs::mojom::DriveError::Type::kCantUploadSharedDriveStorageFull:
       OnEndCopy(
-          GURL(), OfficeFilesUploadResult::kCloudQuotaFull,
-          base::UTF16ToUTF8(
+          base::unexpected(base::UTF16ToUTF8(
               base::i18n::MessageFormatter::FormatWithNumberedArgs(
                   l10n_util::GetStringUTF16(
                       copy ? IDS_OFFICE_UPLOAD_ERROR_FREE_UP_SPACE_TO_COPY
@@ -509,17 +501,18 @@
                   // multi-files is added.
                   1,
                   l10n_util::GetStringUTF16(
-                      IDS_OFFICE_CLOUD_PROVIDER_GOOGLE_DRIVE_SHORT))));
+                      IDS_OFFICE_CLOUD_PROVIDER_GOOGLE_DRIVE_SHORT)))),
+          OfficeFilesUploadResult::kCloudQuotaFull);
       break;
     case drivefs::mojom::DriveError::Type::kPinningFailedDiskFull:
       LOG(ERROR) << "Pinning failed, disk full";
-      OnEndCopy(GURL(), OfficeFilesUploadResult::kPinningFailedDiskFull,
-                GetGenericErrorMessage());
+      OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                OfficeFilesUploadResult::kPinningFailedDiskFull);
       break;
     default:
       LOG(ERROR) << "Cloud error";
-      OnEndCopy(GURL(), OfficeFilesUploadResult::kCloudError,
-                GetGenericErrorMessage());
+      OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                OfficeFilesUploadResult::kCloudError);
   }
 }
 
@@ -527,8 +520,8 @@
     drive::util::ConnectionStatusType status) {
   if (status != drive::util::DRIVE_CONNECTED) {
     LOG(ERROR) << "Lost connection to Drive during upload";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kNoConnection,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kNoConnection);
   }
 }
 
@@ -539,8 +532,8 @@
   if (error != drive::FILE_ERROR_OK) {
     if (timed_out) {
       LOG(ERROR) << "Drive Metadata error";
-      OnEndCopy(GURL(), OfficeFilesUploadResult::kCloudMetadataError,
-                GetGenericErrorMessage());
+      OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                OfficeFilesUploadResult::kCloudMetadataError);
     } else {
       alternate_url_poll_timer_.Start(
           FROM_HERE, base::Milliseconds(kAlternateUrlPollInterval),
@@ -553,8 +546,8 @@
   if (!hosted_url.is_valid()) {
     if (timed_out) {
       LOG(ERROR) << "Invalid alternate URL - Drive editing unavailable";
-      OnEndCopy(GURL(), OfficeFilesUploadResult::kCloudMetadataError,
-                GetGenericErrorMessage());
+      OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                OfficeFilesUploadResult::kCloudMetadataError);
     } else {
       alternate_url_poll_timer_.Start(
           FROM_HERE, base::Milliseconds(kAlternateUrlPollInterval),
@@ -569,8 +562,8 @@
   if (hosted_url.host() != "docs.google.com") {
     if (timed_out) {
       LOG(ERROR) << "Unexpected alternate URL - Drive editing unavailable";
-      OnEndCopy(GURL(), OfficeFilesUploadResult::kCloudMetadataError,
-                GetGenericErrorMessage());
+      OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+                OfficeFilesUploadResult::kCloudMetadataError);
     } else {
       alternate_url_poll_timer_.Start(
           FROM_HERE, base::Milliseconds(kAlternateUrlPollInterval),
@@ -589,8 +582,8 @@
 void DriveUploadHandler::CheckAlternateUrl(bool timed_out) {
   if (!drive_integration_service_) {
     LOG(ERROR) << "No Drive integration service";
-    OnEndCopy(GURL(), OfficeFilesUploadResult::kOtherError,
-              GetGenericErrorMessage());
+    OnEndCopy(base::unexpected(GetGenericErrorMessage()),
+              OfficeFilesUploadResult::kOtherError);
     return;
   }
 
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.h b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.h
index 6524249..e2353f7 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.h
+++ b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.h
@@ -6,12 +6,14 @@
 #define CHROME_BROWSER_UI_WEBUI_ASH_CLOUD_UPLOAD_DRIVE_UPLOAD_HANDLER_H_
 
 #include <memory>
+#include <string>
 
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/types/expected.h"
 #include "chrome/browser/ash/drive/drive_integration_service.h"
 #include "chrome/browser/ash/drive/file_system_util.h"
 #include "chrome/browser/ash/extensions/file_manager/scoped_suppress_drive_notifications_for_path.h"
@@ -55,33 +57,26 @@
   ~DriveUploadHandler() override;
 
   // Starts the upload workflow:
-  //    - Copy IO task.
-  //    - Sync to Drive.
-  //    - |ConvertToMoveOrUndoUpload| if required.
-  // If the upload is supposed to be a move to Drive, delete the source file in
-  // |ConvertToMoveOrUndoUpload|. Initiated by the `Upload` static method.
+  // - Copy the file via an IO task.
+  // - Sync to Drive.
+  // - Remove the source file in case of a move operation. Move mode of the
+  //   `CopyOrMoveIOTask` is not used because the source file should only be
+  //   deleted at the end of the sync operation.
+  // Initiated by the `Upload` static method.
   void Run(UploadCallback callback);
 
   // Updates the progress notification for the upload workflow (copy + syncing).
   void UpdateProgressNotification();
 
-  // Called upon a copy to Drive success or failure. If required, through
-  // |ConvertToMoveOrUndoUpload|, complete or undo the operation. Then call
-  // |OnEndUpload| to end the upload.
-  void OnEndCopy(GURL hosted_url,
-                 OfficeFilesUploadResult result,
-                 std::string error_message = "");
-
-  // If the copy to Drive was successful, delete source file to convert the copy
-  // to Drive to a move to Drive. If the copy to Drive was unsuccessful, delete
-  // the destination file to reverse the effects of the upload.
-  void ConvertToMoveOrUndoUpload(OfficeFilesUploadResult result);
+  // Called upon a copy to Drive success or failure. If required, complete or
+  // undo the operation. Then call |OnEndUpload| to end the upload.
+  void OnEndCopy(base::expected<GURL, std::string> hosted_url,
+                 OfficeFilesUploadResult result_metric);
 
   // Ends the upload by showing any complete or error notifications. Runs the
   // upload callback.
-  void OnEndUpload(GURL hosted_url,
-                   OfficeFilesUploadResult result,
-                   std::string error_message = "");
+  void OnEndUpload(base::expected<GURL, std::string> hosted_url,
+                   OfficeFilesUploadResult result_metric);
 
   // Callback for when ImmediatelyUpload() is called on DriveFS.
   void ImmediatelyUploadDone(drive::FileError error);
@@ -95,9 +90,8 @@
   // error.
   void OnCopyStatus(const ::file_manager::io_task::ProgressStatus& status);
 
-  // Observes delete IO task status updates from delete task introduced in
-  // |ConvertToMoveOrUndoUpload|. Call |OnEndUpload| once the delete is
-  // finished.
+  // Observes delete IO task status updates from the delete task for cleaning up
+  // the source file. Calls `OnEndUpload` once the delete is finished.
   void OnDeleteStatus(const ::file_manager::io_task::ProgressStatus& status);
 
   // Find the base::File::Error error returned by the IO Task and convert it to
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_browsing_data_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_browsing_data_browsertest.cc
index 4896a876..0cc7df1 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_browsing_data_browsertest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_browsing_data_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/test/test_future.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/profiles/profile.h"
@@ -616,8 +617,14 @@
   EXPECT_THAT(GetIwaUsage(url_info2), 0);
 }
 
+// TODO(https://crbug.com/1475108): Flaky on Linux Debug bots.
+#if BUILDFLAG(IS_LINUX) && !defined(NDEBUG)
+#define MAYBE_ClearBrowserDataTimeRanged DISABLED_ClearBrowserDataTimeRanged
+#else
+#define MAYBE_ClearBrowserDataTimeRanged ClearBrowserDataTimeRanged
+#endif
 IN_PROC_BROWSER_TEST_F(IsolatedWebAppBrowsingDataClearingTest,
-                       ClearBrowserDataTimeRanged) {
+                       MAYBE_ClearBrowserDataTimeRanged) {
   auto cache_test_server = std::make_unique<net::EmbeddedTestServer>();
   cache_test_server->AddDefaultHandlers(
       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
diff --git a/chrome/browser/webauthn/android/webauthn_request_delegate_android.cc b/chrome/browser/webauthn/android/webauthn_request_delegate_android.cc
index 4eb5f06..fcbe605 100644
--- a/chrome/browser/webauthn/android/webauthn_request_delegate_android.cc
+++ b/chrome/browser/webauthn/android/webauthn_request_delegate_android.cc
@@ -86,6 +86,9 @@
         ChromeWebAuthnCredentialsDelegateFactory::GetFactory(
             content::WebContents::FromRenderFrameHost(frame_host))
             ->GetDelegateForFrame(frame_host);
+    if (!credentials_delegate) {
+      return;
+    }
     credentials_delegate->SetAndroidHybridAvailable(
         ChromeWebAuthnCredentialsDelegate::AndroidHybridAvailable(
             !hybrid_callback_.is_null()));
@@ -119,9 +122,12 @@
         ChromeWebAuthnCredentialsDelegateFactory::GetFactory(
             content::WebContents::FromRenderFrameHost(frame_host))
             ->GetDelegateForFrame(frame_host);
-    credentials_delegate->NotifyWebAuthnRequestAborted();
-    credentials_delegate->SetAndroidHybridAvailable(
-        ChromeWebAuthnCredentialsDelegate::AndroidHybridAvailable(false));
+
+    if (credentials_delegate) {
+      credentials_delegate->NotifyWebAuthnRequestAborted();
+      credentials_delegate->SetAndroidHybridAvailable(
+          ChromeWebAuthnCredentialsDelegate::AndroidHybridAvailable(false));
+    }
   } else {
     touch_to_fill_controller_->Close();
   }
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 2d3beac..2699926 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1692706016-231e232b3d2e6382a9ee38888e9d3216d46f8334.profdata
+chrome-chromeos-amd64-generic-main-1692748490-cf7b63f9c2c5965d797ad5438fe772addddbe769.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 453df0e2..2a84018 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1692727167-a75b067add08f6ba64a5e7f9bed5dddadbff3736.profdata
+chrome-linux-main-1692748490-059814464a245ff6ec1ffbeb3f27859a4364dc9e.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 94e5e4f..284cdc0 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1692741483-70c10d25884f445c21d557791fa3d363734ac012.profdata
+chrome-mac-arm-main-1692763051-079caecd41759739d3cd6b841578f4593e1161f0.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index e36584a..c0cab4a 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1692727167-7eae91b2022c958f699cbeb318c3d1a0b89d5570.profdata
+chrome-mac-main-1692748490-db4ea11fd5ba56541a2c7902af7d1c2ec032a075.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index d758a922..1cca64a 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1692716378-0dce133d23bbd3396bff61bb3ae7375c8ca78a31.profdata
+chrome-win32-main-1692759583-9a309c9a686b1305c815bf6cc22c73827cd402d3.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index a617603..79da74a2 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1692737847-5f2e9348dec0a0a0ca265724b1abb08da009c83e.profdata
+chrome-win64-main-1692759583-af1c7bb64db63e8c1f9804548ecc44ebb7dc0050.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8580574..0bc8271b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3367,6 +3367,7 @@
         "../browser/extensions/error_console/error_console_browsertest.cc",
         "../browser/extensions/error_console/error_console_test_observer.cc",
         "../browser/extensions/error_console/error_console_test_observer.h",
+        "../browser/extensions/event_metrics_browsertest.cc",
         "../browser/extensions/events_apitest.cc",
         "../browser/extensions/extension_action_runner_browsertest.cc",
         "../browser/extensions/extension_api_frame_id_map_browsertest.cc",
@@ -3734,6 +3735,7 @@
         "../browser/ui/views/autofill/payments/card_unmask_otp_input_dialog_browsertest.cc",
         "../browser/ui/views/autofill/payments/credit_card_access_manager_browsertest.cc",
         "../browser/ui/views/autofill/payments/offer_notification_bubble_views_browsertest.cc",
+        "../browser/ui/views/autofill/payments/offer_notification_bubble_views_pixel_browsertest.cc",
         "../browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc",
         "../browser/ui/views/autofill/payments/virtual_card_selection_dialog_browsertest.cc",
         "../browser/ui/views/autofill/payments/webauthn_dialog_browsertest.cc",
diff --git a/chrome/test/data/extensions/events/metrics/event_page/background.js b/chrome/test/data/extensions/events/metrics/event_page/background.js
new file mode 100644
index 0000000..5bf2589
--- /dev/null
+++ b/chrome/test/data/extensions/events/metrics/event_page/background.js
@@ -0,0 +1,6 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.webNavigation.onCompleted.addListener((details) => {
+});
diff --git a/chrome/test/data/extensions/events/metrics/event_page/manifest.json b/chrome/test/data/extensions/events/metrics/event_page/manifest.json
new file mode 100644
index 0000000..11ef9ba
--- /dev/null
+++ b/chrome/test/data/extensions/events/metrics/event_page/manifest.json
@@ -0,0 +1,10 @@
+{
+  "name": "Event Page",
+  "version": "0.1",
+  "manifest_version": 2,
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": false
+  },
+  "permissions": ["webNavigation"]
+}
diff --git a/chrome/test/data/extensions/events/metrics/persistent_background_page/background.js b/chrome/test/data/extensions/events/metrics/persistent_background_page/background.js
new file mode 100644
index 0000000..5bf2589
--- /dev/null
+++ b/chrome/test/data/extensions/events/metrics/persistent_background_page/background.js
@@ -0,0 +1,6 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.webNavigation.onCompleted.addListener((details) => {
+});
diff --git a/chrome/test/data/extensions/events/metrics/persistent_background_page/manifest.json b/chrome/test/data/extensions/events/metrics/persistent_background_page/manifest.json
new file mode 100644
index 0000000..99061d9
--- /dev/null
+++ b/chrome/test/data/extensions/events/metrics/persistent_background_page/manifest.json
@@ -0,0 +1,10 @@
+{
+  "name": "Persistent Background Page",
+  "version": "0.1",
+  "manifest_version": 2,
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": true
+  },
+  "permissions": ["webNavigation"]
+}
diff --git a/chrome/test/data/extensions/events/metrics/service_worker/background.js b/chrome/test/data/extensions/events/metrics/service_worker/background.js
new file mode 100644
index 0000000..5bf2589
--- /dev/null
+++ b/chrome/test/data/extensions/events/metrics/service_worker/background.js
@@ -0,0 +1,6 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.webNavigation.onCompleted.addListener((details) => {
+});
diff --git a/chrome/test/data/extensions/events/metrics/service_worker/manifest.json b/chrome/test/data/extensions/events/metrics/service_worker/manifest.json
new file mode 100644
index 0000000..6fe8de6e
--- /dev/null
+++ b/chrome/test/data/extensions/events/metrics/service_worker/manifest.json
@@ -0,0 +1,9 @@
+{
+  "name": "Service Worker",
+  "version": "0.1",
+  "manifest_version": 3,
+  "background": {
+    "service_worker": "background.js"
+  },
+  "permissions": ["webNavigation"]
+}
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn
index 1ab5664..4a2b72d4 100644
--- a/chrome/test/data/webui/settings/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -98,6 +98,7 @@
 
     "device_page/audio_page_test.ts",
     "device_page/customize_button_row_test.ts",
+    "device_page/customize_buttons_subsection_test.ts",
     "device_page/customize_mouse_buttons_subpage_test.ts",
     "device_page/customize_tablet_buttons_subpage_test.ts",
     "device_page/customize_pen_buttons_subpage_test.ts",
diff --git a/chrome/test/data/webui/settings/chromeos/device_page/customize_buttons_subsection_test.ts b/chrome/test/data/webui/settings/chromeos/device_page/customize_buttons_subsection_test.ts
new file mode 100644
index 0000000..69c51d0
--- /dev/null
+++ b/chrome/test/data/webui/settings/chromeos/device_page/customize_buttons_subsection_test.ts
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://os-settings/lazy_load.js';
+import 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
+
+import {CustomizeButtonsSubsectionElement} from 'chrome://os-settings/lazy_load.js';
+import {fakeGraphicsTabletButtonActions, fakeGraphicsTablets} from 'chrome://os-settings/os_settings.js';
+import {assert} from 'chrome://resources/js/assert_ts.js';
+import {assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
+
+suite('<customize-buttons-subsection>', () => {
+  let customizeButtonsSubsection: CustomizeButtonsSubsectionElement;
+
+  setup(() => {
+    assert(window.trustedTypes);
+    document.body.innerHTML = window.trustedTypes.emptyHTML;
+  });
+
+  teardown(async () => {
+    if (!customizeButtonsSubsection) {
+      return;
+    }
+    customizeButtonsSubsection.remove();
+    await flushTasks();
+  });
+
+  async function initializeCustomizeButtonsSubsection() {
+    customizeButtonsSubsection =
+        document.createElement(CustomizeButtonsSubsectionElement.is);
+    customizeButtonsSubsection.set(
+        'actionList', fakeGraphicsTabletButtonActions);
+    customizeButtonsSubsection.set(
+        'buttonRemappingList',
+        fakeGraphicsTablets[0]!.settings!.penButtonRemappings);
+    document.body.appendChild(customizeButtonsSubsection);
+    return await flushTasks();
+  }
+
+  test('Initialize customize buttons subsection', async () => {
+    await initializeCustomizeButtonsSubsection();
+    assertTrue(!!customizeButtonsSubsection);
+    assertTrue(!!customizeButtonsSubsection.get('buttonRemappingList'));
+  });
+});
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index 7efc6b9..e77a2a6 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -205,6 +205,10 @@
  ['DevicePageAudioPage', 'device_page/audio_page_test.js'],
  ['DevicePageCustomizeButtonRow', 'device_page/customize_button_row_test.js'],
  [
+   'DevicePageCustomizeButtonsSubsection',
+   'device_page/customize_buttons_subsection_test.js'
+ ],
+ [
    'DevicePageCustomizeMouseButtonsSubpage',
    'device_page/customize_mouse_buttons_subpage_test.js', {
      enabled: [
diff --git a/chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.cc b/chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.cc
index d874eb1..6f1a0b206 100644
--- a/chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.cc
+++ b/chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.cc
@@ -52,9 +52,10 @@
   return context;
 }
 
-KeyedService* LocalSearchServiceProxyFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+LocalSearchServiceProxyFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* /*context*/) const {
-  return new LocalSearchServiceProxy();
+  return std::make_unique<LocalSearchServiceProxy>();
 }
 
 }  // namespace ash::local_search_service
diff --git a/chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.h b/chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.h
index dd28acd..374c753f 100644
--- a/chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.h
+++ b/chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy_factory.h
@@ -37,7 +37,7 @@
   // BrowserContextKeyedServiceFactory:
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index 1d52d9c..19510f6 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-117-5845.27-1690199357-benchmark-117.0.5911.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-118-5938.4-1692617964-benchmark-118.0.5963.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 69ff3a9..94e3146 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-117-5845.39-1690194808-benchmark-117.0.5911.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-118-5938.13-1692612678-benchmark-118.0.5963.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index df486fd..150fbe6 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-117-5845.39-1690192731-benchmark-117.0.5911.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-118-5938.4-1692610741-benchmark-118.0.5963.0-r1-redacted.afdo.xz
diff --git a/components/android_autofill/DIR_METADATA b/components/android_autofill/DIR_METADATA
new file mode 100644
index 0000000..bc280336
--- /dev/null
+++ b/components/android_autofill/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/autofill/COMMON_METADATA"
diff --git a/components/autofill/core/browser/autofill_client.cc b/components/autofill/core/browser/autofill_client.cc
index f6a29cc..11e8719c 100644
--- a/components/autofill/core/browser/autofill_client.cc
+++ b/components/autofill/core/browser/autofill_client.cc
@@ -190,7 +190,7 @@
   // ChromeAutofillClient (Chrome Desktop & Android) implements this.
 }
 
-void AutofillClient::ShowVirtualCardErrorDialog(
+void AutofillClient::ShowAutofillErrorDialog(
     const AutofillErrorDialogContext& context) {
   // This is overridden by platform subclasses. Currently only
   // ChromeAutofillClient (Chrome Desktop & Android) implements this.
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index 3282129..19601c3 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -791,13 +791,12 @@
   virtual void OnVirtualCardDataAvailable(
       const VirtualCardManualFallbackBubbleOptions& options);
 
-  // Called when some virtual card retrieval errors happened. Will show the
-  // error dialog with virtual card related messages. The type of error dialog
-  // that is shown will match the `type` in `context`. If the
+  // Shows an error dialog when card retrieval errors happen. The type of error
+  // dialog that is shown will match the `type` in `context`. If the
   // `server_returned_title` and `server_returned_description` in `context` are
-  // both set, the virtual card error dialog that is displayed will have these
-  // fields displayed for the title and description, respectively.
-  virtual void ShowVirtualCardErrorDialog(
+  // both set, the error dialog that is displayed will have these fields
+  // displayed for the title and description, respectively.
+  virtual void ShowAutofillErrorDialog(
       const AutofillErrorDialogContext& context);
 
   // Show/dismiss the progress dialog which contains a throbber and a text
diff --git a/components/autofill/core/browser/payments/autofill_error_dialog_context.cc b/components/autofill/core/browser/payments/autofill_error_dialog_context.cc
index 590124c..a8879efd 100644
--- a/components/autofill/core/browser/payments/autofill_error_dialog_context.cc
+++ b/components/autofill/core/browser/payments/autofill_error_dialog_context.cc
@@ -8,7 +8,7 @@
 
 // static
 AutofillErrorDialogContext
-AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
     bool is_permanent_error) {
   AutofillErrorDialogContext autofill_error_dialog_context;
   autofill_error_dialog_context.type =
diff --git a/components/autofill/core/browser/payments/autofill_error_dialog_context.h b/components/autofill/core/browser/payments/autofill_error_dialog_context.h
index a9c0df2..ff9bdf5 100644
--- a/components/autofill/core/browser/payments/autofill_error_dialog_context.h
+++ b/components/autofill/core/browser/payments/autofill_error_dialog_context.h
@@ -35,7 +35,7 @@
   // Returns an AutofillErrorDialogContext that is type
   // kVirtualCardPermanentError if `is_permanent_error` is true, and type
   // kVirtualCardTemporaryError if `is_permanent_error` is false.
-  static AutofillErrorDialogContext WithPermanentOrTemporaryError(
+  static AutofillErrorDialogContext WithVirtualCardPermanentOrTemporaryError(
       bool is_permanent_error);
 
   AutofillErrorDialogContext();
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc
index 0fc2964..710e909 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -417,8 +417,8 @@
   if (challenge_options.empty()) {
     accessor_->OnCreditCardFetched(CreditCardFetchResult::kTransientError,
                                    nullptr, u"");
-    client_->ShowVirtualCardErrorDialog(
-        AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+    client_->ShowAutofillErrorDialog(
+        AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
             /*is_permanent_error=*/true));
     Reset();
     autofill_metrics::LogServerCardUnmaskResult(
@@ -733,8 +733,8 @@
     // If it is an virtual card retrieval error, we don't want to invoke the CVC
     // authentication afterwards. Instead reset all states, notify accessor and
     // invoke the error dialog.
-    client_->ShowVirtualCardErrorDialog(
-        AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+    client_->ShowAutofillErrorDialog(
+        AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
             /*is_permanent_error=*/response.failure_type ==
             payments::FullCardRequest::
                 VIRTUAL_CARD_RETRIEVAL_PERMANENT_FAILURE));
@@ -1260,11 +1260,11 @@
     // Error fields returned in the server response are more detailed than the
     // virtual card temporary/permanent error messages stored on the client, so
     // prefer the server-returned fields if they exist.
-    client_->ShowVirtualCardErrorDialog(
+    client_->ShowAutofillErrorDialog(
         *response_details.autofill_error_dialog_context);
   } else {
-    client_->ShowVirtualCardErrorDialog(
-        AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+    client_->ShowAutofillErrorDialog(
+        AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
             /*is_permanent_error=*/result ==
             AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure));
   }
@@ -1307,8 +1307,8 @@
     NOTREACHED();
     accessor_->OnCreditCardFetched(CreditCardFetchResult::kTransientError,
                                    nullptr, u"");
-    client_->ShowVirtualCardErrorDialog(
-        AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+    client_->ShowAutofillErrorDialog(
+        AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
             /*is_permanent_error=*/false));
     Reset();
     return;
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index 3180269..a70ecd36 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -3079,7 +3079,7 @@
   // Expect the CreditCardAccessManager to end the session.
   EXPECT_EQ(accessor_->result(), CreditCardFetchResult::kTransientError);
   EXPECT_FALSE(otp_authenticator_->on_challenge_option_selected_invoked());
-  EXPECT_TRUE(autofill_client_.virtual_card_error_dialog_shown());
+  EXPECT_TRUE(autofill_client_.autofill_error_dialog_shown());
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
   EXPECT_FALSE(fido_authenticator().authenticate_invoked());
 #endif
@@ -3113,7 +3113,7 @@
       AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
       response);
 
-  EXPECT_TRUE(autofill_client_.virtual_card_error_dialog_shown());
+  EXPECT_TRUE(autofill_client_.autofill_error_dialog_shown());
   const AutofillErrorDialogContext& displayed_error_dialog_context =
       autofill_client_.autofill_error_dialog_context();
   EXPECT_EQ(*displayed_error_dialog_context.server_returned_title,
diff --git a/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc b/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
index 7321f19..cc5dc0c 100644
--- a/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
+++ b/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
@@ -180,8 +180,8 @@
   // Show the virtual card permanent error dialog if server explicitly returned
   // vcn permanent error, show temporary error dialog for the rest failure cases
   // since currently only virtual card is supported.
-  autofill_client_->ShowVirtualCardErrorDialog(
-      AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+  autofill_client_->ShowAutofillErrorDialog(
+      AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
           /*is_permanent_error=*/result ==
           AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure));
   if (requester_) {
@@ -355,11 +355,11 @@
   // If the server returned error dialog fields to be displayed, we prefer them
   // since they will be more detailed to the specific error that occurred.
   if (response_details.autofill_error_dialog_context) {
-    autofill_client_->ShowVirtualCardErrorDialog(
+    autofill_client_->ShowAutofillErrorDialog(
         *response_details.autofill_error_dialog_context);
   } else {
-    autofill_client_->ShowVirtualCardErrorDialog(
-        AutofillErrorDialogContext::WithPermanentOrTemporaryError(
+    autofill_client_->ShowAutofillErrorDialog(
+        AutofillErrorDialogContext::WithVirtualCardPermanentOrTemporaryError(
             /*is_permanent_error=*/result ==
             AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure));
   }
diff --git a/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
index 4c5360f..81d5776 100644
--- a/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
@@ -227,7 +227,7 @@
       /*context_token=*/"context_token_from_previous_unmask_response",
       kTestBillingCustomerNumber);
   // Verify error dialog is shown.
-  EXPECT_TRUE(autofill_client_.virtual_card_error_dialog_shown());
+  EXPECT_TRUE(autofill_client_.autofill_error_dialog_shown());
   // Ensure the OTP authenticator is reset.
   EXPECT_TRUE(OtpAuthenticatorContextToken().empty());
   ASSERT_TRUE(requester_->did_succeed().has_value());
@@ -267,7 +267,7 @@
       /*context_token=*/"context_token_from_previous_unmask_response",
       kTestBillingCustomerNumber);
   // Verify error dialog is shown.
-  EXPECT_TRUE(autofill_client_.virtual_card_error_dialog_shown());
+  EXPECT_TRUE(autofill_client_.autofill_error_dialog_shown());
   // Ensure the OTP authenticator is reset.
   EXPECT_TRUE(OtpAuthenticatorContextToken().empty());
   ASSERT_TRUE(requester_->did_succeed().has_value());
@@ -311,7 +311,7 @@
         AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
         /*real_pan=*/"", server_returned_decline_details);
     // Verify error dialog is shown.
-    EXPECT_TRUE(autofill_client_.virtual_card_error_dialog_shown());
+    EXPECT_TRUE(autofill_client_.autofill_error_dialog_shown());
     if (server_returned_decline_details) {
       AutofillErrorDialogContext context =
           autofill_client_.autofill_error_dialog_context();
@@ -367,7 +367,7 @@
   OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kTryAgainFailure,
                   /*real_pan=*/"");
   // Verify error dialog is shown.
-  EXPECT_TRUE(autofill_client_.virtual_card_error_dialog_shown());
+  EXPECT_TRUE(autofill_client_.autofill_error_dialog_shown());
   // Ensure the OTP authenticator is reset.
   EXPECT_TRUE(OtpAuthenticatorContextToken().empty());
   ASSERT_TRUE(requester_->did_succeed().has_value());
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h
index 7414ff7..1c2de48 100644
--- a/components/autofill/core/browser/test_autofill_client.h
+++ b/components/autofill/core/browser/test_autofill_client.h
@@ -442,9 +442,9 @@
 
   PopupHidingReason popup_hiding_reason() { return popup_hidden_reason_; }
 
-  void ShowVirtualCardErrorDialog(
+  void ShowAutofillErrorDialog(
       const AutofillErrorDialogContext& context) override {
-    virtual_card_error_dialog_shown_ = true;
+    autofill_error_dialog_shown_ = true;
     autofill_error_dialog_context_ = context;
   }
 
@@ -616,14 +616,11 @@
     return offer_to_save_credit_card_bubble_was_shown_.value();
   }
 
-  void set_virtual_card_error_dialog_shown(
-      bool virtual_card_error_dialog_shown) {
-    virtual_card_error_dialog_shown_ = virtual_card_error_dialog_shown;
+  void set_autofill_error_dialog_shown(bool autofill_error_dialog_shown) {
+    autofill_error_dialog_shown_ = autofill_error_dialog_shown;
   }
 
-  bool virtual_card_error_dialog_shown() {
-    return virtual_card_error_dialog_shown_;
-  }
+  bool autofill_error_dialog_shown() { return autofill_error_dialog_shown_; }
 
   bool virtual_card_error_dialog_is_permanent_error() {
     return autofill_error_dialog_context().type ==
@@ -744,7 +741,7 @@
 
   bool confirm_save_iban_locally_called_ = false;
 
-  bool virtual_card_error_dialog_shown_ = false;
+  bool autofill_error_dialog_shown_ = false;
 
   // Context parameters that are used to display an error dialog during card
   // number retrieval. This context will have information that the autofill
diff --git a/components/commerce_strings.grdp b/components/commerce_strings.grdp
index 2b84999c..813af7e 100644
--- a/components/commerce_strings.grdp
+++ b/components/commerce_strings.grdp
@@ -325,6 +325,9 @@
     <message name="IDS_DISCOUNT_CODE_COPY_BUTTON_TEXT" desc="The copy button text. User uses this button to copy the discount code, so that they can paste the code during checkout.">
       Copy
     </message>
+    <message name="IDS_TWO_STRINGS_CONNECTOR" desc="This is used to connect two sentences together by using a ending period and a space. The first sentence does not contain an ending period, but the second sentence will.">
+      <ph name="FIRST_STRING">$1<ex>Use this code at checkout</ex></ph>. <ph name="SECOND_STRING">$2<ex>Valid until Aug 15 2023.</ex></ph>
+    </message>
     <if expr="use_titlecase">
       <message name="IDS_DISCOUNT_TERMS_AND_CONDITIONS" desc="This text is used in two places. 1) Use as title for the 'Terms and condition' dialog which shows users the additional qualification of the discount. 2) Use as a linked text in the discount dialog, when user clicks the text, it opens the 'Terms and conditions' dialog.">
         Terms and Conditions
diff --git a/components/commerce_strings_grdp/IDS_TWO_STRINGS_CONNECTOR.png.sha1 b/components/commerce_strings_grdp/IDS_TWO_STRINGS_CONNECTOR.png.sha1
new file mode 100644
index 0000000..774d4b90
--- /dev/null
+++ b/components/commerce_strings_grdp/IDS_TWO_STRINGS_CONNECTOR.png.sha1
@@ -0,0 +1 @@
+6b8ca901540b474cbe90b9b1493d6d02ad115e0a
\ No newline at end of file
diff --git a/components/exo/wayland/protocol/aura-shell.xml b/components/exo/wayland/protocol/aura-shell.xml
index 06623fc..7d988f52 100644
--- a/components/exo/wayland/protocol/aura-shell.xml
+++ b/components/exo/wayland/protocol/aura-shell.xml
@@ -786,7 +786,7 @@
     </event>
   </interface>
 
-  <interface name="zaura_toplevel" version="56">
+  <interface name="zaura_toplevel" version="58">
     <description summary="aura shell interface to the toplevel shell">
       An interface to the toplevel shell, which allows the
       client to access shell specific functionality.
@@ -1247,6 +1247,39 @@
       <arg name="serial" type="uint" summary="serial for the original; rotation event" />
       <arg name="handled" type="uint" enum="rotate_handled_state" summary="whether or not the rotation was successful" />
     </request>
+
+    <request name="set_can_maximize" since="58">
+      <description summary="Hint that the toplevel surface can be maximized">
+        Hints to the window manager that the toplevel surface can be maximized.
+      </description>
+    </request>
+
+    <request name="unset_can_maximize" since="58">
+      <description summary="Hint that the toplevel surface should not be maximized">
+        Hints to the window manager that the toplevel surface should not be
+        maximized. Note that the window manager might still request the client
+        to be maximized. In such an event, the client should respect the
+        window manager's request and maximize. It may unset the maximized state
+        afterwards.
+      </description>
+    </request>
+
+    <request name="set_can_fullscreen" since="58">
+      <description summary="Hint that the toplevel surface can enter fullscreen">
+        Hints to the window manager that the toplevel surface can enter
+        fullscreen.
+      </description>
+    </request>
+
+    <request name="unset_can_fullscreen" since="58">
+      <description summary="Hint that the toplevel surface should not enter fullscreen">
+        Hints to the window manager that the toplevel surface should not be
+        enter fullscreen. Note that the window manager might still request the
+        client enter fullscreen. In such an event, the client should respect the
+        window manager's request and enter fullscreen. It may exit fullscreen
+        afterwards.
+      </description>
+    </request>
   </interface>
 
   <interface name="zaura_popup" version="46">
diff --git a/components/exo/wayland/wayland_aura_shell_server_test.cc b/components/exo/wayland/wayland_aura_shell_server_test.cc
index 9279e632..fc63aae 100644
--- a/components/exo/wayland/wayland_aura_shell_server_test.cc
+++ b/components/exo/wayland/wayland_aura_shell_server_test.cc
@@ -449,5 +449,45 @@
   EXPECT_EQ(2, observer->overview_exited_call_count);
 }
 
+TEST_F(WaylandAuraShellServerTest, SetCanMaximizeAndFullscreen) {
+  auto keys = SetupClientSurfaces();
+  AttachBufferToSurfaces();
+
+  std::unique_ptr<zaura_toplevel> zaura_toplevel;
+  PostToClientAndWait([&](test::TestClient* client) {
+    auto* data = client->GetDataAs<ClientData>();
+    zaura_toplevel.reset(zaura_shell_get_aura_toplevel_for_xdg_toplevel(
+        client->globals().aura_shell.get(),
+        data->test_surfaces_list[0].xdg_toplevel.get()));
+  });
+
+  WaylandXdgSurface* xdg_surface =
+      test::server_util::GetUserDataForResource<WaylandXdgSurface>(
+          server_.get(), keys[0].shell_surface_key);
+  ASSERT_TRUE(xdg_surface);
+
+  auto* widget = xdg_surface->shell_surface->GetWidget();
+
+  PostToClientAndWait([&](test::TestClient* client) {
+    zaura_toplevel_set_can_maximize(zaura_toplevel.get());
+  });
+  EXPECT_TRUE(widget->widget_delegate()->CanMaximize());
+
+  PostToClientAndWait([&](test::TestClient* client) {
+    zaura_toplevel_unset_can_maximize(zaura_toplevel.get());
+  });
+  EXPECT_FALSE(widget->widget_delegate()->CanMaximize());
+
+  PostToClientAndWait([&](test::TestClient* client) {
+    zaura_toplevel_set_can_fullscreen(zaura_toplevel.get());
+  });
+  EXPECT_TRUE(widget->widget_delegate()->CanFullscreen());
+
+  PostToClientAndWait([&](test::TestClient* client) {
+    zaura_toplevel_unset_can_fullscreen(zaura_toplevel.get());
+  });
+  EXPECT_FALSE(widget->widget_delegate()->CanFullscreen());
+}
+
 }  // namespace
 }  // namespace exo::wayland
diff --git a/components/exo/wayland/zaura_shell.cc b/components/exo/wayland/zaura_shell.cc
index 9560882..ce3dc10b 100644
--- a/components/exo/wayland/zaura_shell.cc
+++ b/components/exo/wayland/zaura_shell.cc
@@ -934,6 +934,14 @@
   shell_surface_->AckRotateFocus(serial, handled);
 }
 
+void AuraToplevel::SetCanMaximize(bool can_maximize) {
+  shell_surface_->SetCanMaximize(can_maximize);
+}
+
+void AuraToplevel::SetCanFullscreen(bool can_fullscreen) {
+  shell_surface_->SetCanFullscreen(can_fullscreen);
+}
+
 void AuraToplevel::IntentToSnap(uint32_t snap_direction) {
   switch (snap_direction) {
     case ZAURA_SURFACE_SNAP_DIRECTION_NONE:
@@ -1557,6 +1565,25 @@
   GetUserDataAs<AuraToplevel>(resource)->AckRotateFocus(serial, handled);
 }
 
+void aura_toplevel_set_can_maximize(wl_client* client, wl_resource* resource) {
+  GetUserDataAs<AuraToplevel>(resource)->SetCanMaximize(true);
+}
+
+void aura_toplevel_unset_can_maximize(wl_client* client,
+                                      wl_resource* resource) {
+  GetUserDataAs<AuraToplevel>(resource)->SetCanMaximize(false);
+}
+
+void aura_toplevel_set_can_fullscreen(wl_client* client,
+                                      wl_resource* resource) {
+  GetUserDataAs<AuraToplevel>(resource)->SetCanFullscreen(true);
+}
+
+void aura_toplevel_unset_can_fullscreen(wl_client* client,
+                                        wl_resource* resource) {
+  GetUserDataAs<AuraToplevel>(resource)->SetCanFullscreen(false);
+}
+
 const struct zaura_toplevel_interface aura_toplevel_implementation = {
     aura_toplevel_set_orientation_lock,
     aura_toplevel_surface_submission_in_pixel_coordinates,
@@ -1584,6 +1611,10 @@
     aura_toplevel_set_shape,
     aura_toplevel_set_top_inset,
     aura_toplevel_ack_rotate_focus,
+    aura_toplevel_set_can_maximize,
+    aura_toplevel_unset_can_maximize,
+    aura_toplevel_set_can_fullscreen,
+    aura_toplevel_unset_can_fullscreen,
 };
 
 void aura_popup_surface_submission_in_pixel_coordinates(wl_client* client,
diff --git a/components/exo/wayland/zaura_shell.h b/components/exo/wayland/zaura_shell.h
index 6db1c9d..589f632 100644
--- a/components/exo/wayland/zaura_shell.h
+++ b/components/exo/wayland/zaura_shell.h
@@ -173,6 +173,8 @@
   void OnRotatePaneFocus(uint32_t serial,
                          ash::FocusCycler::Direction direction,
                          bool restart);
+  void SetCanMaximize(bool can_maximize);
+  void SetCanFullscreen(bool can_fullscreen);
 
   raw_ptr<ShellSurface, DanglingUntriaged | ExperimentalAsh> shell_surface_;
   const raw_ptr<SerialTracker, ExperimentalAsh> serial_tracker_;
diff --git a/components/exo/window_properties.h b/components/exo/window_properties.h
index 385e8a5..35ff88a 100644
--- a/components/exo/window_properties.h
+++ b/components/exo/window_properties.h
@@ -30,6 +30,7 @@
 // use the logic that if we can resize, we can maximise. Should only be set to
 // true for Sommelier-based windows.
 extern const ui::ClassProperty<bool>* const kMaximumSizeForResizabilityOnly;
+
 }  // namespace exo
 
 #endif  // COMPONENTS_EXO_WINDOW_PROPERTIES_H_
diff --git a/components/segmentation_platform/internal/database/ukm_database_backend.cc b/components/segmentation_platform/internal/database/ukm_database_backend.cc
index c11da65..d6d3340f 100644
--- a/components/segmentation_platform/internal/database/ukm_database_backend.cc
+++ b/components/segmentation_platform/internal/database/ukm_database_backend.cc
@@ -255,6 +255,10 @@
 
 void UkmDatabaseBackend::DeleteEntriesOlderThan(base::Time time) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (status_ != Status::INIT_SUCCESS) {
+    return;
+  }
+
   std::vector<UrlId> deleted_urls =
       metrics_table_.DeleteEventsBeforeTimestamp(time);
   url_table_.RemoveUrls(deleted_urls);
@@ -263,6 +267,7 @@
 
 void UkmDatabaseBackend::DeleteAllUrls() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK_EQ(status_, Status::INIT_SUCCESS);
 
   // Remove all metrics associated with any URL, but retain the metrics that are
   // not keyed on URL.
diff --git a/components/segmentation_platform/internal/database/ukm_database_backend_unittest.cc b/components/segmentation_platform/internal/database/ukm_database_backend_unittest.cc
index 16c6b7a..f81a1eef 100644
--- a/components/segmentation_platform/internal/database/ukm_database_backend_unittest.cc
+++ b/components/segmentation_platform/internal/database/ukm_database_backend_unittest.cc
@@ -555,6 +555,7 @@
   backend_->UpdateUrlForUkmSource(10, kUrl1, true);
   backend_->RemoveUrls({kUrl1}, /*all_urls=*/false);
   backend_->RemoveUrls({kUrl1}, /*all_urls=*/true);
+  backend_->DeleteEntriesOlderThan(base::Time() - base::Seconds(10));
 
   UkmDatabase::QueryList queries;
   queries.emplace(0, UkmDatabase::CustomSqlQuery("SELECT bad query", {}));
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index d45faad..367c7ff 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -825,8 +825,8 @@
 
   gpu::Mailbox mailbox = gpu::Mailbox::GenerateForSharedImage();
   bool result = shared_image_factory_->CreateSharedImage(
-      mailbox, format, size, color_space, kBottomLeft_GrSurfaceOrigin,
-      kUnpremul_SkAlphaType, gpu::kNullSurfaceHandle, kUsage,
+      mailbox, format, size, color_space, kTopLeft_GrSurfaceOrigin,
+      kPremul_SkAlphaType, gpu::kNullSurfaceHandle, kUsage,
       std::string(debug_label));
   if (!result) {
     DLOG(ERROR) << "Failed to create shared image.";
diff --git a/components/viz/service/transitions/surface_animation_manager.cc b/components/viz/service/transitions/surface_animation_manager.cc
index bbcc52e..5d1c8e3 100644
--- a/components/viz/service/transitions/surface_animation_manager.cc
+++ b/components/viz/service/transitions/surface_animation_manager.cc
@@ -99,14 +99,11 @@
 // drawn.
 // |shared_element_quad| is the quad providing the geometry to draw this shared
 // element's content.
-// |y_flipped| indicates if the texture should be flipped vertically when
-// composited.
 // |id| is a reference to the texture which provides the content for this shared
 // element.
 void ReplaceSharedElementWithTexture(
     CompositorRenderPass* target_render_pass,
     const SharedElementDrawQuad& shared_element_quad,
-    bool y_flipped,
     ResourceId resource_id) {
   auto* copied_quad_state =
       target_render_pass->CreateAndAppendSharedQuadState();
@@ -125,7 +122,7 @@
       /*uv_top_left=*/gfx::PointF(0, 0),
       /*uv_bottom_right=*/gfx::PointF(1, 1),
       /*background_color=*/SkColors::kTransparent,
-      /*vertex_opacity=*/vertex_opacity, y_flipped,
+      /*vertex_opacity=*/vertex_opacity, /*y_flipped=*/false,
       /*nearest_neighbor=*/false,
       /*secure_output_only=*/false,
       /*protected_video_type=*/gfx::ProtectedVideoType::kClear);
@@ -233,10 +230,8 @@
 
       resource_list->push_back(transferable_resource);
 
-      // GPU textures are flipped but software bitmaps are not.
-      bool y_flipped = !transferable_resource.is_software;
       ReplaceSharedElementWithTexture(&copy_pass, shared_element_quad,
-                                      y_flipped, resource_list->back().id);
+                                      resource_list->back().id);
       return true;
     }
   }
diff --git a/content/browser/fenced_frame/fenced_frame_browsertest.cc b/content/browser/fenced_frame/fenced_frame_browsertest.cc
index 9386032..0845bb2 100644
--- a/content/browser/fenced_frame/fenced_frame_browsertest.cc
+++ b/content/browser/fenced_frame/fenced_frame_browsertest.cc
@@ -4834,7 +4834,7 @@
         {
             {"click", reporting_url},
         },
-        /*reporting_ad_macro_map=*/FencedFrameReporter::ReportingMacroMap());
+        /*reporting_ad_macros=*/FencedFrameReporter::ReportingMacros());
     // Set empty reporting url for seller.
     fenced_frame_reporter->OnUrlMappingReady(
         blink::FencedFrame::ReportingDestination::kSeller, {{"click", GURL()}});
diff --git a/content/browser/fenced_frame/fenced_frame_reporter.cc b/content/browser/fenced_frame/fenced_frame_reporter.cc
index 121c453..7fec860 100644
--- a/content/browser/fenced_frame/fenced_frame_reporter.cc
+++ b/content/browser/fenced_frame/fenced_frame_reporter.cc
@@ -257,14 +257,14 @@
 void FencedFrameReporter::OnUrlMappingReady(
     blink::FencedFrame::ReportingDestination reporting_destination,
     ReportingUrlMap reporting_url_map,
-    absl::optional<ReportingMacroMap> reporting_ad_macro_map) {
+    absl::optional<ReportingMacros> reporting_ad_macros) {
   auto it = reporting_metadata_.find(reporting_destination);
   DCHECK(it != reporting_metadata_.end());
   DCHECK(!it->second.reporting_url_map);
-  DCHECK(!it->second.reporting_ad_macro_map);
+  DCHECK(!it->second.reporting_ad_macros);
 
   it->second.reporting_url_map = std::move(reporting_url_map);
-  it->second.reporting_ad_macro_map = std::move(reporting_ad_macro_map);
+  it->second.reporting_ad_macros = std::move(reporting_ad_macros);
   auto pending_events = std::exchange(it->second.pending_events, {});
   for (const auto& pending_event : pending_events) {
     std::string ignored_error_message;
@@ -410,7 +410,7 @@
     // Check that reportEvent to custom destination URLs with macro
     // substitution is allowed in this context. (i.e., The macro map has a
     // value.)
-    if (!reporting_destination_info.reporting_ad_macro_map.has_value()) {
+    if (!reporting_destination_info.reporting_ad_macros.has_value()) {
       error_message =
           "This frame attempted to send a report to a custom destination URL "
           "with macro substitution, which is not supported by the API that "
@@ -447,16 +447,10 @@
       return false;
     }
 
-    // Substitute macros in the specified URL using the macro map.
-    // TODO(qingxinwu): Lift these changes up out of FencedFrameReporter into
-    // the code that constructs the reporting ad macro map.
-    std::vector<std::pair<std::string, std::string>> macro_map;
-    for (const auto& entry :
-         reporting_destination_info.reporting_ad_macro_map.value()) {
-      macro_map.emplace_back("${" + entry.first + "}", entry.second);
-    }
+    // Substitute macros in the specified URL using the macros.
     url = GURL(SubstituteMappedStrings(
-        absl::get<DestinationURLEvent>(event_variant).url.spec(), macro_map));
+        absl::get<DestinationURLEvent>(event_variant).url.spec(),
+        reporting_destination_info.reporting_ad_macros.value()));
     url::Origin destination_origin = url::Origin::Create(url);
 
     // Check whether the destination URL has an allowed origin.
@@ -724,14 +718,13 @@
 }
 
 base::flat_map<blink::FencedFrame::ReportingDestination,
-               FencedFrameReporter::ReportingMacroMap>
-FencedFrameReporter::GetAdMacroMapForTesting() {
-  base::flat_map<blink::FencedFrame::ReportingDestination, ReportingMacroMap>
-      out;
+               FencedFrameReporter::ReportingMacros>
+FencedFrameReporter::GetAdMacrosForTesting() {
+  base::flat_map<blink::FencedFrame::ReportingDestination, ReportingMacros> out;
   for (const auto& reporting_metadata : reporting_metadata_) {
-    if (reporting_metadata.second.reporting_ad_macro_map) {
+    if (reporting_metadata.second.reporting_ad_macros) {
       out.emplace(reporting_metadata.first,
-                  *reporting_metadata.second.reporting_ad_macro_map);
+                  *reporting_metadata.second.reporting_ad_macros);
     }
   }
   return out;
diff --git a/content/browser/fenced_frame/fenced_frame_reporter.h b/content/browser/fenced_frame/fenced_frame_reporter.h
index 16adfdf..19ebadf 100644
--- a/content/browser/fenced_frame/fenced_frame_reporter.h
+++ b/content/browser/fenced_frame/fenced_frame_reporter.h
@@ -46,7 +46,7 @@
 
 // An event to be sent to a custom url.
 // `url` is the custom destination url, and the request is sent as a GET.
-// TODO(gtanzer): Macros are substituted using the `ReportingMacroMap`.
+// Macros are substituted using the `ReportingMacros`.
 struct DestinationURLEvent {
   GURL url;
 };
@@ -60,7 +60,7 @@
  public:
   using ReportingUrlMap = base::flat_map<std::string, GURL>;
 
-  using ReportingMacroMap = base::flat_map<std::string, std::string>;
+  using ReportingMacros = std::vector<std::pair<std::string, std::string>>;
 
   using PrivateAggregationRequests =
       std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>;
@@ -145,11 +145,10 @@
   // destination, so it can discard reports for that destination, and provide
   // errors messages for subsequent SendReporter() using that destination.
   //
-  // `reporting_ad_macro_map` is absl::nullopt unless when
-  // `reporting_destination` is kBuyer. If it is learned that there are no ad
-  // macros for kBuyer, should be called with an empty ReportingMacroMap, so it
-  // can discard macro reports, and provide errors messages for subsequent
-  // SendReporter().
+  // `reporting_ad_macros` is absl::nullopt unless when `reporting_destination`
+  // is kBuyer. If it is learned that there are no ad macros for kBuyer, should
+  // be called with an empty ReportingMacros, so it can discard macro reports,
+  // and provide errors messages for subsequent SendReporter().
   //
   // TODO(https://crbug.com/1409133): Consider investing in outputting error to
   // correct frame, if it still exists. `frame_tree_node_id` somewhat does this,
@@ -159,7 +158,7 @@
   void OnUrlMappingReady(
       blink::FencedFrame::ReportingDestination reporting_destination,
       ReportingUrlMap reporting_url_map,
-      absl::optional<ReportingMacroMap> reporting_ad_macro_map = absl::nullopt);
+      absl::optional<ReportingMacros> reporting_ad_macros = absl::nullopt);
 
   // Sends a report for the specified event, using the ReportingUrlMap
   // associated with `reporting_destination`. If the map for
@@ -174,7 +173,7 @@
   //   sent.
   // * a `DestinationURLEvent`, which contains a `url`
   //   * Sends a GET to `url`.
-  //   * TODO(gtanzer): Substitutes macros from the ReportingMacroMap.
+  //   * Substitutes macros from the ReportingMacros.
   //
   // Returns false and populated `error_message` and `console_message_level` if
   // no network request was attempted, unless the reporting URL map for
@@ -232,12 +231,12 @@
   GetAdBeaconMapForTesting();
 
   // Returns a copy of the internal reporting metadata's
-  // `reporting_ad_macro_map`, so it can be validated in tests. Only includes ad
-  // macro maps for which maps have been received - i.e., if wait for
+  // `reporting_ad_macros`, so it can be validated in tests. Only includes ad
+  // macros for which maps have been received - i.e., if wait for
   // OnUrlMappingReady() to be invoked for a reporting destination, it is not
   // included in the returned map.
-  base::flat_map<blink::FencedFrame::ReportingDestination, ReportingMacroMap>
-  GetAdMacroMapForTesting();
+  base::flat_map<blink::FencedFrame::ReportingDestination, ReportingMacros>
+  GetAdMacrosForTesting();
 
   // Returns `received_pa_events_`, so that it can be validated in tests. Should
   // only be called from tests.
@@ -296,10 +295,10 @@
     // `pending_events`, and only sent once this is populated.
     absl::optional<ReportingUrlMap> reporting_url_map;
 
-    // If null, the reporting ad macro map has yet to be received, and any
-    // reports that are attempted to be sent to custom URLs will be added to
+    // If null, the reporting ad macros has yet to be received, and any reports
+    // that are attempted to be sent to custom URLs will be added to
     // `pending_events`, and only sent once this is populated.
-    absl::optional<ReportingMacroMap> reporting_ad_macro_map;
+    absl::optional<ReportingMacros> reporting_ad_macros;
 
     // Pending report strings received while `reporting_url_map` was
     // absl::nullopt. Once the map is received, this is cleared, and reports are
diff --git a/content/browser/fenced_frame/fenced_frame_reporter_unittest.cc b/content/browser/fenced_frame/fenced_frame_reporter_unittest.cc
index 68d8323..b5806ccd 100644
--- a/content/browser/fenced_frame/fenced_frame_reporter_unittest.cc
+++ b/content/browser/fenced_frame/fenced_frame_reporter_unittest.cc
@@ -421,7 +421,7 @@
   reporter->OnUrlMappingReady(
       blink::FencedFrame::ReportingDestination::kBuyer,
       /*reporting_url_map=*/{{"event_type", report_destination3_}},
-      /*reporting_ad_macro_map=*/FencedFrameReporter::ReportingMacroMap());
+      /*reporting_ad_macros=*/FencedFrameReporter::ReportingMacros());
   EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
 
   // Make reports. Each should be sent immediately.
@@ -542,7 +542,7 @@
   reporter->OnUrlMappingReady(
       blink::FencedFrame::ReportingDestination::kBuyer,
       /*reporting_url_map=*/{{"event_type", report_destination3_}},
-      /*reporting_ad_macro_map=*/FencedFrameReporter::ReportingMacroMap());
+      /*reporting_ad_macros=*/FencedFrameReporter::ReportingMacros());
   EXPECT_EQ(test_url_loader_factory_.NumPending(), 5);
   ValidateRequest((*test_url_loader_factory_.pending_requests())[3].request,
                   report_destination3_, "event_data");
@@ -624,7 +624,7 @@
   reporter->OnUrlMappingReady(
       blink::FencedFrame::ReportingDestination::kBuyer,
       /*reporting_url_map=*/{},
-      /*reporting_ad_macro_map=*/FencedFrameReporter::ReportingMacroMap());
+      /*reporting_ad_macros=*/FencedFrameReporter::ReportingMacros());
   EXPECT_EQ(test_url_loader_factory_.NumPending(), 1);
   ValidateRequest((*test_url_loader_factory_.pending_requests())[0].request,
                   report_destination_, absl::nullopt);
@@ -649,7 +649,7 @@
     reporter->OnUrlMappingReady(
         blink::FencedFrame::ReportingDestination::kBuyer,
         /*reporting_url_map=*/{{}},
-        /*reporting_ad_macro_map=*/FencedFrameReporter::ReportingMacroMap());
+        /*reporting_ad_macros=*/FencedFrameReporter::ReportingMacros());
     EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
 
     std::string error_message;
@@ -683,7 +683,7 @@
   // Receive a buyer mapping whose `reporting_ad_macro_map` is absl::nullopt.
   reporter->OnUrlMappingReady(blink::FencedFrame::ReportingDestination::kBuyer,
                               /*reporting_url_map=*/{{}},
-                              /*reporting_ad_macro_map=*/absl::nullopt);
+                              /*reporting_ad_macros=*/absl::nullopt);
   EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
 
   std::string error_message;
@@ -752,11 +752,12 @@
           {{report_destination_origin_}});
 
   // Receive buyer mapping.
-  reporter->OnUrlMappingReady(blink::FencedFrame::ReportingDestination::kBuyer,
-                              /*reporting_url_map=*/{{}},
-                              /*reporting_ad_macro_map=*/
-                              FencedFrameReporter::ReportingMacroMap(
-                                  {{"FOO", "foosub"}, {"BAR", "barsub"}}));
+  reporter->OnUrlMappingReady(
+      blink::FencedFrame::ReportingDestination::kBuyer,
+      /*reporting_url_map=*/{{}},
+      /*reporting_ad_macros=*/
+      FencedFrameReporter::ReportingMacros(
+          {{"${FOO}", "foosub"}, {"${BAR}", "barsub"}}));
   EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
 
   GURL report_destination_template{
@@ -795,8 +796,8 @@
   reporter->OnUrlMappingReady(
       blink::FencedFrame::ReportingDestination::kBuyer,
       /*reporting_url_map=*/{{}},
-      /*reporting_ad_macro_map=*/
-      FencedFrameReporter::ReportingMacroMap({{"FOO", "${FOO}${FOO}"}}));
+      /*reporting_ad_macros=*/
+      FencedFrameReporter::ReportingMacros({{"${FOO}", "${FOO}${FOO}"}}));
   EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
 
   GURL report_destination_template{
@@ -819,6 +820,48 @@
                   report_destination_substituted, absl::nullopt);
 }
 
+// Test macro substitution for reports to custom destination URLs, where the
+// macro is nested (e.g., ${${FOO}}). The macros are not substituted
+// recursively.
+TEST_F(FencedFrameReporterTest, CustomDestinationURLNestedMacro) {
+  scoped_refptr<FencedFrameReporter> reporter =
+      FencedFrameReporter::CreateForFledge(
+          shared_url_loader_factory(), browser_context(),
+          /*direct_seller_is_seller=*/false, &private_aggregation_manager_,
+          main_frame_origin_,
+          /*winner_origin=*/report_destination_origin_,
+          /*allowed_reporting_origins=*/
+          {{report_destination_origin_}});
+
+  // Receive buyer mapping.
+  reporter->OnUrlMappingReady(
+      blink::FencedFrame::ReportingDestination::kBuyer,
+      /*reporting_url_map=*/{{}},
+      /*reporting_ad_macros=*/
+      FencedFrameReporter::ReportingMacros(
+          {{"${FOO}", "foo"}, {"${${FOO}}", "${FOO}"}}));
+  EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
+
+  GURL report_destination_template{
+      "https://report_destination.test?foo=${${FOO}}&foo2=${FOO}"};
+  GURL report_destination_substituted{
+      "https://"
+      "report_destination.test?foo=${FOO}&foo2=foo"};
+
+  // Send a request from an allowed origin. (It should succeed.)
+  std::string error_message;
+  blink::mojom::ConsoleMessageLevel console_message_level =
+      blink::mojom::ConsoleMessageLevel::kError;
+  EXPECT_TRUE(reporter->SendReport(
+      DestinationURLEvent(report_destination_template),
+      blink::FencedFrame::ReportingDestination::kBuyer, main_rfh_impl(),
+      network::AttributionReportingRuntimeFeatures(), error_message,
+      console_message_level));
+  EXPECT_EQ(test_url_loader_factory_.NumPending(), 1);
+  ValidateRequest((*test_url_loader_factory_.pending_requests())[0].request,
+                  report_destination_substituted, absl::nullopt);
+}
+
 // Test allowlist for reports to custom destination URLs.
 TEST_F(FencedFrameReporterTest, CustomDestinationURLAllowlist) {
   scoped_refptr<FencedFrameReporter> reporter =
@@ -834,7 +877,7 @@
   reporter->OnUrlMappingReady(
       blink::FencedFrame::ReportingDestination::kBuyer,
       /*reporting_url_map=*/{{"event_type", report_destination_}},
-      /*reporting_ad_macro_map=*/FencedFrameReporter::ReportingMacroMap());
+      /*reporting_ad_macros=*/FencedFrameReporter::ReportingMacros());
   EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
 
   // Send a request to an allowed origin. (It should succeed.)
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc
index 7359282..9bee3fd 100644
--- a/content/browser/interest_group/auction_runner_unittest.cc
+++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -1388,8 +1388,8 @@
                    FencedFrameReporter::ReportingUrlMap>
         ad_beacon_map;
     base::flat_map<blink::FencedFrame::ReportingDestination,
-                   FencedFrameReporter::ReportingMacroMap>
-        ad_macro_map;
+                   FencedFrameReporter::ReportingMacros>
+        ad_macros;
     std::map<std::string, PrivateAggregationRequests>
         private_aggregation_event_map;
     std::vector<blink::InterestGroupKey> interest_groups_that_bid;
@@ -1831,8 +1831,8 @@
         InterestGroupManagerImpl::ReportType::kSendReportTo);
     result_.ad_beacon_map =
         reporter_->fenced_frame_reporter()->GetAdBeaconMapForTesting();
-    result_.ad_macro_map =
-        reporter_->fenced_frame_reporter()->GetAdMacroMapForTesting();
+    result_.ad_macros =
+        reporter_->fenced_frame_reporter()->GetAdMacrosForTesting();
     result_.debug_loss_report_urls =
         interest_group_manager_->TakeReportUrlsOfType(
             InterestGroupManagerImpl::ReportType::kDebugLoss);
@@ -3326,10 +3326,10 @@
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/4"))))));
 
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "4")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "4")))));
 
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
@@ -3686,10 +3686,10 @@
                 ReportingDestination::kBuyer,
                 testing::ElementsAre(testing::Pair(
                     "click", GURL("https://buyer-reporting.example.com/4"))))));
-    EXPECT_THAT(result_.ad_macro_map,
+    EXPECT_THAT(result_.ad_macros,
                 testing::UnorderedElementsAre(testing::Pair(
                     ReportingDestination::kBuyer,
-                    testing::ElementsAre(testing::Pair("campaign", "4")))));
+                    testing::ElementsAre(testing::Pair("${campaign}", "4")))));
     EXPECT_THAT(
         private_aggregation_manager_.TakePrivateAggregationRequests(),
         testing::UnorderedElementsAre(
@@ -3779,10 +3779,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/4"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "4")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "4")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -3867,10 +3867,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/4"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "4")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "4")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -3939,10 +3939,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/4"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "4")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "4")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -4661,10 +4661,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/6"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "6")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "6")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -4817,10 +4817,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/2"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "2")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "2")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -5213,10 +5213,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/2"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "2")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "2")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -5320,10 +5320,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/2"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "2")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "2")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -5426,10 +5426,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/2"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "2")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "2")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -5553,10 +5553,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/2"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "2")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "2")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -5641,10 +5641,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/2"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "2")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "2")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -5962,10 +5962,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/2"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "2")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "2")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
@@ -6329,7 +6329,7 @@
           testing::Pair(ReportingDestination::kComponentSeller,
                         testing::ElementsAre()),
           testing::Pair(ReportingDestination::kBuyer, testing::ElementsAre())));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer, testing::ElementsAre())));
   EXPECT_THAT(
@@ -6403,7 +6403,7 @@
   EXPECT_THAT(result_.report_urls, testing::UnorderedElementsAre());
   EXPECT_THAT(result_.ad_beacon_map,
               testing::UnorderedElementsAreArray(kEmptyAdBeaconMap));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer, testing::ElementsAre())));
 
@@ -8926,10 +8926,11 @@
                   testing::ElementsAre(testing::Pair(
                       "click",
                       GURL("https://buyer-reporting.example.com/4"))))));
-      EXPECT_THAT(result_.ad_macro_map,
-                  testing::UnorderedElementsAre(testing::Pair(
-                      ReportingDestination::kBuyer,
-                      testing::ElementsAre(testing::Pair("campaign", "4")))));
+      EXPECT_THAT(
+          result_.ad_macros,
+          testing::UnorderedElementsAre(testing::Pair(
+              ReportingDestination::kBuyer,
+              testing::ElementsAre(testing::Pair("${campaign}", "4")))));
       EXPECT_THAT(
           private_aggregation_manager_.TakePrivateAggregationRequests(),
           testing::UnorderedElementsAre(
@@ -9146,10 +9147,11 @@
                   testing::ElementsAre(testing::Pair(
                       "click",
                       GURL("https://buyer-reporting.example.com/4"))))));
-      EXPECT_THAT(result_.ad_macro_map,
-                  testing::UnorderedElementsAre(testing::Pair(
-                      ReportingDestination::kBuyer,
-                      testing::ElementsAre(testing::Pair("campaign", "4")))));
+      EXPECT_THAT(
+          result_.ad_macros,
+          testing::UnorderedElementsAre(testing::Pair(
+              ReportingDestination::kBuyer,
+              testing::ElementsAre(testing::Pair("${campaign}", "4")))));
       EXPECT_THAT(
           private_aggregation_manager_.TakePrivateAggregationRequests(),
           testing::UnorderedElementsAre(
@@ -9363,10 +9365,10 @@
               ReportingDestination::kBuyer,
               testing::ElementsAre(testing::Pair(
                   "click", GURL("https://buyer-reporting.example.com/4"))))));
-  EXPECT_THAT(result_.ad_macro_map,
+  EXPECT_THAT(result_.ad_macros,
               testing::UnorderedElementsAre(testing::Pair(
                   ReportingDestination::kBuyer,
-                  testing::ElementsAre(testing::Pair("campaign", "4")))));
+                  testing::ElementsAre(testing::Pair("${campaign}", "4")))));
   EXPECT_THAT(
       private_aggregation_manager_.TakePrivateAggregationRequests(),
       testing::UnorderedElementsAre(
diff --git a/content/browser/interest_group/interest_group_auction_reporter.cc b/content/browser/interest_group/interest_group_auction_reporter.cc
index b8398d63..c4cb44a 100644
--- a/content/browser/interest_group/interest_group_auction_reporter.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter.cc
@@ -868,10 +868,19 @@
       break;
     }
   }
+  // Convert `bidder_ad_macro_map` to a vector of (${macro_name}, macro_value)
+  // pairs as fenced frame reporter expects.
+  absl::optional<std::vector<std::pair<std::string, std::string>>>
+      bidder_macros = absl::nullopt;
+  if (bidder_ad_macro_map.has_value()) {
+    bidder_macros.emplace();
+    for (const auto& [macro_name, macro_value] : bidder_ad_macro_map.value()) {
+      bidder_macros->emplace_back("${" + macro_name + "}", macro_value);
+    }
+  }
   fenced_frame_reporter_->OnUrlMappingReady(
       blink::FencedFrame::ReportingDestination::kBuyer,
-      std::move(validated_bidder_ad_beacon_map),
-      std::move(bidder_ad_macro_map));
+      std::move(validated_bidder_ad_beacon_map), std::move(bidder_macros));
 
   if (bidder_report_url) {
     if (!IsEventLevelReportingUrlValid(*bidder_report_url)) {
diff --git a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
index dc0013d..67c4ab0 100644
--- a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
@@ -571,10 +571,15 @@
       {"cluck", GURL("https://buyer.cluck.test/")},
   };
 
-  const FencedFrameReporter::ReportingMacroMap kAdMacroMap = {
+  const base::flat_map<std::string, std::string> kAdMacroMap = {
       {"campaign", "123"},
   };
 
+  // The converted `kAdMacroMap` that is passed to fenced frame reporter.
+  const FencedFrameReporter::ReportingMacros kAdMacros = {
+      {"${campaign}", "123"},
+  };
+
   base::HistogramTester histogram_tester_;
 
   // SharedURLLoaderFactory used for reports. Reports are short-circuited by the
@@ -2028,11 +2033,11 @@
 };
 
 TEST_F(InterestGroupAuctionReporterAdMacroReportingEnabledTest,
-       SingleSellerReportMacroMap) {
+       SingleSellerReportMacros) {
   SetUpAndStartSingleSellerAuction();
-  // The macro map should be empty from the start.
+  // The macros should be empty from the start.
   EXPECT_THAT(interest_group_auction_reporter_->fenced_frame_reporter()
-                  ->GetAdMacroMapForTesting(),
+                  ->GetAdMacrosForTesting(),
               testing::UnorderedElementsAre());
 
   WaitForReportResultAndRunCallback(kSellerScriptUrl,
@@ -2041,10 +2046,10 @@
   WaitForReportWinAndRunCallback(/*report_url=*/absl::nullopt,
                                  /*ad_beacon_map=*/{}, kAdMacroMap);
   EXPECT_THAT(interest_group_auction_reporter_->fenced_frame_reporter()
-                  ->GetAdMacroMapForTesting(),
+                  ->GetAdMacrosForTesting(),
               testing::UnorderedElementsAre(testing::Pair(
                   blink::FencedFrame::ReportingDestination::kBuyer,
-                  testing::UnorderedElementsAreArray(kAdMacroMap))));
+                  testing::UnorderedElementsAreArray(kAdMacros))));
 
   // Invoking the callback has no effect on macro maps. Fenced frames navigated
   // to the winning ad use them to trigger reports, so no need to hold them back
@@ -2053,17 +2058,17 @@
 
   WaitForCompletion();
   EXPECT_THAT(interest_group_auction_reporter_->fenced_frame_reporter()
-                  ->GetAdMacroMapForTesting(),
+                  ->GetAdMacrosForTesting(),
               testing::UnorderedElementsAre(testing::Pair(
                   blink::FencedFrame::ReportingDestination::kBuyer,
-                  testing::UnorderedElementsAreArray(kAdMacroMap))));
+                  testing::UnorderedElementsAreArray(kAdMacros))));
 }
 
 TEST_F(InterestGroupAuctionReporterAdMacroReportingEnabledTest,
-       ComponentAuctionReportMacroMap) {
+       ComponentAuctionReportMacros) {
   SetUpAndStartComponentAuction();
   EXPECT_THAT(interest_group_auction_reporter_->fenced_frame_reporter()
-                  ->GetAdMacroMapForTesting(),
+                  ->GetAdMacrosForTesting(),
               testing::UnorderedElementsAre());
 
   WaitForReportResultAndRunCallback(kSellerScriptUrl,
@@ -2075,10 +2080,10 @@
   WaitForReportWinAndRunCallback(/*report_url=*/absl::nullopt,
                                  /*ad_beacon_map=*/{}, kAdMacroMap);
   EXPECT_THAT(interest_group_auction_reporter_->fenced_frame_reporter()
-                  ->GetAdMacroMapForTesting(),
+                  ->GetAdMacrosForTesting(),
               testing::UnorderedElementsAre(testing::Pair(
                   blink::FencedFrame::ReportingDestination::kBuyer,
-                  testing::UnorderedElementsAreArray(kAdMacroMap))));
+                  testing::UnorderedElementsAreArray(kAdMacros))));
 
   // Invoking the callback has no effect on per-destination reporting maps.
   // Fenced frames navigated to the winning ad use them to trigger reports, so
@@ -2088,10 +2093,10 @@
 
   WaitForCompletion();
   EXPECT_THAT(interest_group_auction_reporter_->fenced_frame_reporter()
-                  ->GetAdMacroMapForTesting(),
+                  ->GetAdMacrosForTesting(),
               testing::UnorderedElementsAre(testing::Pair(
                   blink::FencedFrame::ReportingDestination::kBuyer,
-                  testing::UnorderedElementsAreArray(kAdMacroMap))));
+                  testing::UnorderedElementsAreArray(kAdMacros))));
 }
 
 }  // namespace
diff --git a/content/browser/loader/keep_alive_url_loader.h b/content/browser/loader/keep_alive_url_loader.h
index a77d3cd..c433b55 100644
--- a/content/browser/loader/keep_alive_url_loader.h
+++ b/content/browser/loader/keep_alive_url_loader.h
@@ -41,27 +41,40 @@
 class PolicyContainerHost;
 
 // A URLLoader for loading a fetch keepalive request via the browser process,
-// including both `fetch(..., {keepalive: true})` and `navigator.sendBeacon()`
-// requests.
+// including requests generated from the following JS API calls:
+//   - fetch(..., {keepalive: true})
+//   - navigator.sendBeacon(...)
+//   - fetchLater(...)
 //
 // To load a keepalive request initiated by a renderer, this loader performs the
 // following logic:
-// 1. Forwards all request loading actions received from a remote of
-//    `mojom::URLLoader` in a renderer to a receiver of `mojom::URLLoader` in
-//    the network service connected by `loader_`.
-// 2. Receives request loading results from the network service, i.e. the remote
-//    of `loader_receiver_`. The URLLoaderClient overrides will be triggered to
-//    process results:
-//    A. For redirect, perform security checks and ask the network service to
-//       follow all subsequent redirects.
-//    B. For non-redirect,
-//       a. If the renderer is still alive, i.e. `forwarding_client_` is
-//          connected, ask it to process the results instead.
-//       b. If the renderer is dead, drop the results.
 //
-// Instances of this class must only be constructed via calling
-// `KeepAliveURLLoaderService`, such that the lifetime of the instances match
-// the lifetime of the keepalive requests.
+// 1. In ctor, stores request data sent from a renderer.
+// 2. In `Start()`, asks the network service to start loading the request, and
+//    then runs throttles to perform checks.
+// 3. Handles request loading results from the network service, i.e. from the
+//    remote of `loader_receiver_` (a mojom::URLLoaderClient):
+//    A. If it is `OnReceiveRedirect()`, this loader performs checks and runs
+//       throttles, and then asks the network service to proceed with redirects
+//       without interacting with renderer. The redirect params are stored for
+//       later use.
+//    B. If it is `OnReceiveResponse()` or `OnComplete()`, this loader does not
+//       process response. Instead, it calls `ForwardURLLoad()` to begin to
+//       forward previously saved mojom::URLLoaderClient calls to the renderer,
+//       if the renderer is still alive; Otherwise, terminating this loader.
+//    C. If a throttle asynchronously asks to cancel the request, similar to B,
+//       the previously stored calls will be forwarded to the renderer.
+//    D. The renderer's response to `ForwardURLLoad()` may be any of
+//       mojom::URLLoader calls, in which they should continue forwarding by
+//       calling `ForwardURLLoader()` again.
+//
+// See the "Longer Redirect Chain" section of the Design Doc for an example
+// call sequence diagram.
+//
+// This class must only be constructed by `KeepAliveURLLoaderService`.
+//
+// The lifetime of an instance is roughly equal to the lifetime of a keepalive
+// request, which may surpass the initiator renderer's lifetime.
 //
 // Design Doc:
 // https://docs.google.com/document/d/1ZzxMMBvpqn8VZBZKnb7Go8TWjnrGcXuLS_USwVVRUvY
@@ -82,7 +95,7 @@
   //
   // `resource_request` must be a keepalive request from a renderer.
   // `forwarding_client` should handle request loading results from the network
-  //     service if it is still connected.
+  // service if it is still connected.
   // `delete_callback` is a callback to delete this object.
   // `policy_container_host` must not be null.
   KeepAliveURLLoader(
diff --git a/content/browser/loader/keep_alive_url_loader_service.cc b/content/browser/loader/keep_alive_url_loader_service.cc
index e8e9ce6..5b58b20 100644
--- a/content/browser/loader/keep_alive_url_loader_service.cc
+++ b/content/browser/loader/keep_alive_url_loader_service.cc
@@ -94,7 +94,9 @@
       delete;
 
   // Returns the pointer to the context for this factory.
-  const std::unique_ptr<FactoryContext>& current_context() const;
+  const std::unique_ptr<FactoryContext>& current_context() const {
+    return loader_factory_receivers_.current_context();
+  }
 
   // Creates a `FactoryContext` to hold a refptr to
   // `network::SharedURLLoaderFactory`, which is constructed with
@@ -104,23 +106,123 @@
       mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
       scoped_refptr<network::SharedURLLoaderFactory>
           subresource_proxying_factory_bundle,
-      scoped_refptr<PolicyContainerHost> policy_container_host);
+      scoped_refptr<PolicyContainerHost> policy_container_host) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    CHECK(policy_container_host);
+    TRACE_EVENT("loading", "KeepAliveURLLoaderFactory::BindFactory");
+
+    // Adds a new factory receiver to the set, binding the pending `receiver`
+    // from to `this` with a new context that has frame-specific data and keeps
+    // reference to `subresource_proxying_factory_bundle`.
+    auto context = std::make_unique<FactoryContext>(
+        subresource_proxying_factory_bundle, std::move(policy_container_host));
+    loader_factory_receivers_.Add(this, std::move(receiver),
+                                  std::move(context));
+  }
 
   // `network::mojom::URLLoaderFactory` overrides:
   void CreateLoaderAndStart(
       mojo::PendingReceiver<network::mojom::URLLoader> receiver,
       int32_t request_id,
       uint32_t options,
-      const network::ResourceRequest& resource_request_in,
+      const network::ResourceRequest& resource_request,
       mojo::PendingRemote<network::mojom::URLLoaderClient> client,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
-      override;
+      override {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    TRACE_EVENT("loading", "KeepAliveURLLoaderFactory::CreateLoaderAndStart",
+                "request_id", request_id);
+
+    if (!resource_request.keepalive) {
+      loader_factory_receivers_.ReportBadMessage(
+          "Unexpected `resource_request` in "
+          "KeepAliveURLLoaderService::CreateLoaderAndStart(): "
+          "resource_request.keepalive must be true");
+      return;
+    }
+    if (resource_request.trusted_params) {
+      // Must use untrusted URLLoaderFactory. If not, the requesting renderer
+      // should be aborted.
+      loader_factory_receivers_.ReportBadMessage(
+          "Unexpected `resource_request` in "
+          "KeepAliveURLLoaderService::CreateLoaderAndStart(): "
+          "resource_request.trusted_params must not be set");
+      return;
+    }
+
+    // Creates a new KeepAliveURLLoader from the factory of the current context
+    // to load `resource_request`.
+    //
+    // At this point, the initiator renderer that triggers this factory method
+    // may have already be gone, e.g. a keepalive request initiated from an
+    // unload handler. But as long as `context` exists, the necessary data for a
+    // loader is ensured to exist.
+    const std::unique_ptr<FactoryContext>& context = current_context();
+
+    // Passes in the pending remote of `client` from a renderer so that `loader`
+    // can forward response back to the renderer.
+    CHECK(context->policy_container_host);
+    auto loader = std::make_unique<KeepAliveURLLoader>(
+        request_id, options, resource_request, std::move(client),
+        traffic_annotation, context->factory,
+        // `context` can be destroyed right at the end of this method if the
+        // caller renderer is already unloaded, meaning `loader` also needs to
+        // hold another refptr to ensure `PolicyContainerHost` alive.
+        context->policy_container_host, service_->browser_context_,
+        CreateThrottles(resource_request),
+        base::PassKey<KeepAliveURLLoaderService>());
+    // Adds a new loader receiver to the set, binding the pending `receiver`
+    // from a renderer to `raw_loader` with `loader` as its context. The set
+    // will keep `loader` alive.
+    auto* raw_loader = loader.get();
+    auto receiver_id = service_->loader_receivers_.Add(
+        raw_loader, std::move(receiver), std::move(loader));
+    raw_loader->set_on_delete_callback(
+        base::BindOnce(&KeepAliveURLLoaderService::RemoveLoader,
+                       base::Unretained(service_), receiver_id));
+
+    if (service_->loader_test_observer_) {
+      raw_loader->SetObserverForTesting(     // IN-TEST
+          service_->loader_test_observer_);  // IN-TEST
+    }
+
+    // `loader` must only be started after the above setup.
+    if (!resource_request.is_fetch_later_api) {
+      raw_loader->Start();
+    }
+  }
   void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
-      override;
+      override {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+    loader_factory_receivers_.Add(
+        this, std::move(receiver),
+        std::make_unique<FactoryContext>(current_context()));
+  }
 
  private:
   std::vector<std::unique_ptr<blink::URLLoaderThrottle>> CreateThrottles(
-      const network::ResourceRequest& resource_request);
+      const network::ResourceRequest& resource_request) {
+    if (service_->url_loader_throttles_getter_for_testing_) {
+      return service_->url_loader_throttles_getter_for_testing_
+          .Run();  // IN-TEST
+    }
+
+    // These throttles are also run by `blink::ThrottlingURLLoader`. However,
+    // they have to be re-run here in case of handling in-browser redirects.
+    // There is already a similar use case that also runs throttles in browser
+    // in `SearchPrefetchRequest::StartPrefetchRequest()`. The review discussion
+    // in https://crrev.com/c/2552723/3 suggests that running them again in
+    // browser is fine.
+    return CreateContentBrowserURLLoaderThrottlesForKeepAlive(
+        resource_request, service_->browser_context_,
+        // The renderer might be gone at any point when a throttle is running in
+        // the KeepAliveURLLoader.
+        /*wc_getter=*/base::BindRepeating([]() -> WebContents* {
+          return nullptr;
+        }),
+        FrameTreeNode::kFrameTreeNodeInvalidId);
+  }
 
   // Guaranteed to exist, as `service_` owns this object.
   raw_ptr<KeepAliveURLLoaderService> service_;
@@ -134,130 +236,6 @@
       loader_factory_receivers_;
 };
 
-const std::unique_ptr<FactoryContext>&
-KeepAliveURLLoaderService::KeepAliveURLLoaderFactory::current_context() const {
-  return loader_factory_receivers_.current_context();
-}
-
-void KeepAliveURLLoaderService::KeepAliveURLLoaderFactory::BindFactory(
-    mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
-    scoped_refptr<network::SharedURLLoaderFactory>
-        subresource_proxying_factory_bundle,
-    scoped_refptr<PolicyContainerHost> policy_container_host) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  CHECK(policy_container_host);
-  TRACE_EVENT("loading", "KeepAliveURLLoaderFactory::BindFactory");
-
-  // Adds a new factory receiver to the set, binding the pending `receiver` from
-  // to `this` with a new context that has frame-specific data and keeps
-  // reference to `subresource_proxying_factory_bundle`.
-  auto context = std::make_unique<FactoryContext>(
-      subresource_proxying_factory_bundle, std::move(policy_container_host));
-  loader_factory_receivers_.Add(this, std::move(receiver), std::move(context));
-}
-
-void KeepAliveURLLoaderService::KeepAliveURLLoaderFactory::CreateLoaderAndStart(
-    mojo::PendingReceiver<network::mojom::URLLoader> receiver,
-    int32_t request_id,
-    uint32_t options,
-    const network::ResourceRequest& resource_request,
-    mojo::PendingRemote<network::mojom::URLLoaderClient> client,
-    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  TRACE_EVENT("loading", "KeepAliveURLLoaderFactory::CreateLoaderAndStart",
-              "request_id", request_id);
-
-  if (!resource_request.keepalive) {
-    loader_factory_receivers_.ReportBadMessage(
-        "Unexpected `resource_request` in "
-        "KeepAliveURLLoaderService::CreateLoaderAndStart(): "
-        "resource_request.keepalive must be true");
-    return;
-  }
-  if (resource_request.trusted_params) {
-    // Must use untrusted URLLoaderFactory. If not, the requesting renderer
-    // should be aborted.
-    loader_factory_receivers_.ReportBadMessage(
-        "Unexpected `resource_request` in "
-        "KeepAliveURLLoaderService::CreateLoaderAndStart(): "
-        "resource_request.trusted_params must not be set");
-    return;
-  }
-
-  // Creates a new KeepAliveURLLoader from the factory of the current context
-  // to load `resource_request`.
-  //
-  // At this point, the initiator renderer that triggers this factory method may
-  // have already be gone, e.g. a keepalive request initiated from an unload
-  // handler. But as long as `context` exists, the necessary data for a loader
-  // is ensured to exist.
-  const std::unique_ptr<FactoryContext>& context = current_context();
-
-  // Passes in the pending remote of `client` from a renderer so that `loader`
-  // can forward response back to the renderer.
-  CHECK(context->policy_container_host);
-  auto loader = std::make_unique<KeepAliveURLLoader>(
-      request_id, options, resource_request, std::move(client),
-      traffic_annotation, context->factory,
-      // `context` can be destroyed right at the end of this method if the
-      // caller renderer is already unloaded, meaning `loader` also needs to
-      // hold another refptr to ensure `PolicyContainerHost` alive.
-      context->policy_container_host, service_->browser_context_,
-      CreateThrottles(resource_request),
-      base::PassKey<KeepAliveURLLoaderService>());
-  // Adds a new loader receiver to the set, binding the pending `receiver` from
-  // a renderer to `raw_loader` with `loader` as its context. The set will keep
-  // `loader` alive.
-  auto* raw_loader = loader.get();
-  auto receiver_id = service_->loader_receivers_.Add(
-      raw_loader, std::move(receiver), std::move(loader));
-  raw_loader->set_on_delete_callback(
-      base::BindOnce(&KeepAliveURLLoaderService::RemoveLoader,
-                     base::Unretained(service_), receiver_id));
-
-  if (service_->loader_test_observer_) {
-    raw_loader->SetObserverForTesting(     // IN-TEST
-        service_->loader_test_observer_);  // IN-TEST
-  }
-
-  // `loader` must only be started after the above setup.
-  if (!resource_request.is_fetch_later_api) {
-    raw_loader->Start();
-  }
-}
-
-void KeepAliveURLLoaderService::KeepAliveURLLoaderFactory::Clone(
-    mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  loader_factory_receivers_.Add(
-      this, std::move(receiver),
-      std::make_unique<FactoryContext>(current_context()));
-}
-
-std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
-KeepAliveURLLoaderService::KeepAliveURLLoaderFactory::CreateThrottles(
-    const network::ResourceRequest& resource_request) {
-  if (service_->url_loader_throttles_getter_for_testing_) {
-    return service_->url_loader_throttles_getter_for_testing_.Run();  // IN-TEST
-  }
-
-  // These throttles are also run by `blink::ThrottlingURLLoader`. However, they
-  // have to be re-run here in case of handling in-browser redirects. There is
-  // already a similar use case that also runs throttles in browser in
-  // `SearchPrefetchRequest::StartPrefetchRequest()`. The review discussion in
-  // https://crrev.com/c/2552723/3 suggests that running them again in browser
-  // is fine.
-  return CreateContentBrowserURLLoaderThrottlesForKeepAlive(
-      resource_request, service_->browser_context_,
-      // The renderer might be gone at any point when a throttle is running in
-      // the KeepAliveURLLoader.
-      /*wc_getter=*/base::BindRepeating([]() -> WebContents* {
-        return nullptr;
-      }),
-      FrameTreeNode::kFrameTreeNodeInvalidId);
-}
-
 KeepAliveURLLoaderService::KeepAliveURLLoaderService(
     BrowserContext* browser_context)
     : browser_context_(browser_context) {
diff --git a/content/browser/loader/keep_alive_url_loader_service.h b/content/browser/loader/keep_alive_url_loader_service.h
index 42df976..bb81b4b2 100644
--- a/content/browser/loader/keep_alive_url_loader_service.h
+++ b/content/browser/loader/keep_alive_url_loader_service.h
@@ -22,8 +22,9 @@
 class BrowserContext;
 class PolicyContainerHost;
 
-// A service that stores bound SharedURLLoaderFactory mojo pipes and the loaders
-// they have created to load fetch keepalive requests.
+// A service that stores bound SharedURLLoaderFactory mojo pipes from renderers
+// of the same storage partition, and the intermediate URLLoader receivers, i.e.
+// KeepAliveURLLoader, they have created to load fetch keepalive requests.
 //
 // A fetch keepalive request is originated from a JS call to
 // `fetch(..., {keepalive: true})` or `navigator.sendBeacon()`. A renderer can
@@ -31,20 +32,26 @@
 // mojom::URLLoaderFactory bound to this service by `BindFactory()`, which also
 // binds RenderFrameHostImpl-specific context with every receiver.
 //
-// Calling the remote `CreateLoaderAndStart()` will create a
-// `KeepAliveURLLoader` in browser. The service is also responsible for keeping
+// Calling the remote `CreateLoaderAndStart()` of a factory will create a
+// `KeepAliveURLLoader` here in browser. The service is responsible for keeping
 // these loaders in `loader_receivers_` until the corresponding request
 // completes or fails.
 //
 // Handling keepalive requests in this service allows a request to continue even
-// if a renderer unloads before completion, i.e. the request is "keepalive".
+// if a renderer unloads before completion, i.e. the request is "keepalive",
+// without needing the renderer to stay extra longer than the necessary time.
 //
 // This service is created and stored in every `StoragePartitionImpl` instance.
+// Hence, its lifetime is the same as the owner StoragePartition for a partition
+// domain, which should be generally longer than any of the renderers spawned
+// from the partition domain.
 //
 // Design Doc:
 // https://docs.google.com/document/d/1ZzxMMBvpqn8VZBZKnb7Go8TWjnrGcXuLS_USwVVRUvY
 class CONTENT_EXPORT KeepAliveURLLoaderService {
  public:
+  // `browser_context` owns the StoragePartition creating the instance of this
+  // service. It must not be null and surpass the lifetime of this service.
   explicit KeepAliveURLLoaderService(BrowserContext* browser_context);
   ~KeepAliveURLLoaderService();
 
@@ -53,12 +60,13 @@
   KeepAliveURLLoaderService& operator=(const KeepAliveURLLoaderService&) =
       delete;
 
-  // Binds the pending `receiver` with this service, using `pending_factory`.
+  // Binds the pending `receiver` with this service, using
+  // `subresource_proxying_factory_bundle`.
   //
   // The remote of `receiver` can be passed to another process, i.e. renderer,
-  // to handle fetch keepalive requests.
+  // from which to create new fetch keepalive requests.
   //
-  // `policy_container_host` is the policy host of the frame that is going to
+  // `policy_container_host` is the policy host of the requester frame going to
   // use the remote of `receiver` to load requests. It must not be null.
   void BindFactory(
       mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
diff --git a/content/browser/preloading/speculation_rules/speculation_host_impl.cc b/content/browser/preloading/speculation_rules/speculation_host_impl.cc
index 1ba17e6..044625c 100644
--- a/content/browser/preloading/speculation_rules/speculation_host_impl.cc
+++ b/content/browser/preloading/speculation_rules/speculation_host_impl.cc
@@ -87,7 +87,7 @@
 }
 
 void SpeculationHostImpl::InitiatePreview(const GURL& url) {
-  if (base::FeatureList::IsEnabled(blink::features::kLinkPreview)) {
+  if (!base::FeatureList::IsEnabled(blink::features::kLinkPreview)) {
     mojo::ReportBadMessage("SH_PREVIEW");
     return;
   }
diff --git a/content/browser/renderer_host/ipc_utils.cc b/content/browser/renderer_host/ipc_utils.cc
index c9319bf..70c3a97 100644
--- a/content/browser/renderer_host/ipc_utils.cc
+++ b/content/browser/renderer_host/ipc_utils.cc
@@ -44,8 +44,12 @@
   return true;
 }
 
-bool VerifyInitiatorOrigin(int process_id,
-                           const url::Origin& initiator_origin) {
+bool VerifyInitiatorOrigin(
+    int process_id,
+    const url::Origin& initiator_origin,
+    RenderFrameHostImpl* current_rfh = nullptr,
+    GURL* navigation_url = nullptr,
+    absl::optional<blink::LocalFrameToken>* initiator_frame_token = nullptr) {
   // TODO(acolwell, nasko): https://crbug.com/1029092: Ensure the precursor of
   // opaque origins matches the origin lock.  One known problematic case are
   // reloads initiated from error pages - see the following
@@ -61,6 +65,80 @@
 
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
   if (!policy->CanAccessDataForOrigin(process_id, initiator_origin)) {
+    if (navigation_url) {
+      static auto* const navigation_url_key =
+          base::debug::AllocateCrashKeyString(
+              "navigation_url", base::debug::CrashKeySize::Size256);
+      base::debug::SetCrashKeyString(
+          navigation_url_key,
+          navigation_url->DeprecatedGetOriginAsURL().spec());
+    }
+    if (initiator_frame_token) {
+      if (RenderFrameHostImpl* initiator_render_frame_host =
+              RenderFrameHostImpl::FromFrameToken(
+                  process_id, initiator_frame_token->value())) {
+        static auto* const initiator_rfh_origin_key =
+            base::debug::AllocateCrashKeyString(
+                "initiator_rfh_origin", base::debug::CrashKeySize::Size256);
+        base::debug::SetCrashKeyString(
+            initiator_rfh_origin_key,
+            initiator_render_frame_host->GetLastCommittedOrigin()
+                .GetDebugString());
+      }
+    }
+
+    if (current_rfh) {
+      auto bool_to_crash_key = [](bool b) { return b ? "true" : "false"; };
+      static auto* const is_main_frame_key =
+          base::debug::AllocateCrashKeyString(
+              "is_main_frame", base::debug::CrashKeySize::Size32);
+      base::debug::SetCrashKeyString(
+          is_main_frame_key, bool_to_crash_key(current_rfh->is_main_frame()));
+
+      static auto* const is_outermost_frame_key =
+          base::debug::AllocateCrashKeyString(
+              "is_outermost_frame", base::debug::CrashKeySize::Size32);
+      base::debug::SetCrashKeyString(
+          is_outermost_frame_key,
+          bool_to_crash_key(current_rfh->IsOutermostMainFrame()));
+
+      static auto* const is_on_initial_empty_document_key =
+          base::debug::AllocateCrashKeyString(
+              "is_on_initial_empty_doc", base::debug::CrashKeySize::Size32);
+      base::debug::SetCrashKeyString(
+          is_on_initial_empty_document_key,
+          bool_to_crash_key(
+              current_rfh->frame_tree_node()->is_on_initial_empty_document()));
+
+      static auto* const last_committed_origin_key =
+          base::debug::AllocateCrashKeyString(
+              "last_committed_origin", base::debug::CrashKeySize::Size256);
+      base::debug::SetCrashKeyString(
+          last_committed_origin_key,
+          current_rfh->GetLastCommittedOrigin().GetDebugString());
+
+      if (current_rfh->GetParentOrOuterDocumentOrEmbedder()) {
+        static auto* const parent_etc_origin_key =
+            base::debug::AllocateCrashKeyString(
+                "parent_etc_origin", base::debug::CrashKeySize::Size256);
+        base::debug::SetCrashKeyString(
+            parent_etc_origin_key,
+            current_rfh->GetParentOrOuterDocumentOrEmbedder()
+                ->GetLastCommittedOrigin()
+                .GetDebugString());
+      }
+
+      if (FrameTreeNode* opener = current_rfh->frame_tree_node()->opener()) {
+        static auto* const opener_origin_key =
+            base::debug::AllocateCrashKeyString(
+                "opener_origin", base::debug::CrashKeySize::Size256);
+        base::debug::SetCrashKeyString(opener_origin_key,
+                                       opener->current_frame_host()
+                                           ->GetLastCommittedOrigin()
+                                           .GetDebugString());
+      }
+    }
+
     bad_message::ReceivedBadMessage(process_id,
                                     bad_message::INVALID_INITIATOR_ORIGIN);
     return false;
@@ -131,8 +209,10 @@
   }
 
   // Verify |params.initiator_origin|.
-  if (!VerifyInitiatorOrigin(process_id, params->initiator_origin))
+  if (!VerifyInitiatorOrigin(process_id, params->initiator_origin, current_rfh,
+                             &params->url, &params->initiator_frame_token)) {
     return false;
+  }
 
   if (params->initiator_base_url) {
     // `initiator_base_url` should only be defined for about:blank and
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 2f1dd8fe..2c55032 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -675,6 +675,7 @@
     blink::mojom::ServiceWorkerStartStatus start_status,
     blink::mojom::ServiceWorkerFetchHandlerType fetch_handler_type,
     bool has_hid_event_handlers,
+    bool has_usb_event_handlers,
     int thread_id,
     blink::mojom::EmbeddedWorkerStartTimingPtr start_timing) {
   TRACE_EVENT0("ServiceWorker", "EmbeddedWorkerInstance::OnStarted");
@@ -715,8 +716,8 @@
   thread_id_ = thread_id;
   inflight_start_info_.reset();
   for (auto& observer : listener_list_) {
-    observer.OnStarted(start_status, fetch_handler_type,
-                       has_hid_event_handlers);
+    observer.OnStarted(start_status, fetch_handler_type, has_hid_event_handlers,
+                       has_usb_event_handlers);
     // |this| may be destroyed here. Fortunately we know there is only one
     // observer in production code.
   }
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h
index 57b0e667..fec72cd 100644
--- a/content/browser/service_worker/embedded_worker_instance.h
+++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -102,7 +102,8 @@
     virtual void OnStarted(
         blink::mojom::ServiceWorkerStartStatus status,
         blink::mojom::ServiceWorkerFetchHandlerType fetch_handler_type,
-        bool has_hid_event_handlers) {}
+        bool has_hid_event_handlers,
+        bool has_usb_event_handlers) {}
 
     // Called when status changed to STOPPING. The renderer has been sent a Stop
     // IPC message and OnStopped() will be called upon successful completion.
@@ -304,6 +305,7 @@
       blink::mojom::ServiceWorkerStartStatus status,
       blink::mojom::ServiceWorkerFetchHandlerType fetch_handler_type,
       bool has_hid_event_handlers,
+      bool has_usb_event_handlers,
       int thread_id,
       blink::mojom::EmbeddedWorkerStartTimingPtr start_timing) override;
   // Resets the embedded worker instance to the initial state. Changes
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index fdbdd01..cf4fbe1 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -70,7 +70,8 @@
   }
   void OnStarted(blink::mojom::ServiceWorkerStartStatus status,
                  blink::mojom::ServiceWorkerFetchHandlerType fetch_handler_type,
-                 bool has_hid_event_handlers) override {
+                 bool has_hid_event_handlers,
+                 bool has_usb_event_handlers) override {
     fetch_handler_type_ = fetch_handler_type;
     RecordEvent(STARTED, absl::nullopt, status);
   }
@@ -441,6 +442,7 @@
     host()->OnStarted(blink::mojom::ServiceWorkerStartStatus::kAbruptCompletion,
                       blink::mojom::ServiceWorkerFetchHandlerType::kNoHandler,
                       /*has_hid_event_handlers=*/false,
+                      /*has_usb_event_handlers=*/false,
                       helper()->GetNextThreadId(),
                       blink::mojom::EmbeddedWorkerStartTiming::New());
   }
@@ -487,6 +489,7 @@
     host()->OnScriptEvaluationStart();
     host()->OnStarted(blink::mojom::ServiceWorkerStartStatus::kNormalCompletion,
                       fetch_handler_type_, /*has_hid_event_handlers=*/false,
+                      /*has_usb_event_handlers=*/false,
                       helper()->GetNextThreadId(),
                       blink::mojom::EmbeddedWorkerStartTiming::New());
   }
diff --git a/content/browser/service_worker/fake_embedded_worker_instance_client.cc b/content/browser/service_worker/fake_embedded_worker_instance_client.cc
index 1dc5dd29..ca1fa1a7 100644
--- a/content/browser/service_worker/fake_embedded_worker_instance_client.cc
+++ b/content/browser/service_worker/fake_embedded_worker_instance_client.cc
@@ -224,7 +224,8 @@
   host_->OnScriptEvaluationStart();
   host_->OnStarted(blink::mojom::ServiceWorkerStartStatus::kNormalCompletion,
                    blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable,
-                   /*has_hid_event_handlers=*/false, helper_->GetNextThreadId(),
+                   /*has_hid_event_handlers=*/false,
+                   /*has_usb_event_handlers=*/false, helper_->GetNextThreadId(),
                    blink::mojom::EmbeddedWorkerStartTiming::New());
 }
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index 2fc2ce4..eb31005 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -125,7 +125,7 @@
       host()->OnStarted(
           blink::mojom::ServiceWorkerStartStatus::kNormalCompletion,
           fetch_handler_type_, /*has_hid_event_handlers=*/false,
-          helper()->GetNextThreadId(),
+          /*has_usb_event_handlers=*/false, helper()->GetNextThreadId(),
           blink::mojom::EmbeddedWorkerStartTiming::New());
     }
 
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index 01cc45b0..c9d8f3d 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -1351,6 +1351,7 @@
     host()->OnScriptEvaluationStart();
     host()->OnStarted(blink::mojom::ServiceWorkerStartStatus::kNormalCompletion,
                       fetch_handler_type_, /*has_hid_event_handlers=*/false,
+                      /*has_usb_event_handlers=*/false,
                       helper()->GetNextThreadId(),
                       blink::mojom::EmbeddedWorkerStartTiming::New());
   }
@@ -1546,7 +1547,8 @@
       host()->OnStarted(
           blink::mojom::ServiceWorkerStartStatus::kAbruptCompletion,
           blink::mojom::ServiceWorkerFetchHandlerType::kNoHandler,
-          /*has_hid_event_handlers=*/false, helper()->GetNextThreadId(),
+          /*has_hid_event_handlers=*/false, /*has_usb_event_handlers=*/false,
+          helper()->GetNextThreadId(),
           blink::mojom::EmbeddedWorkerStartTiming::New());
     }
 
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index ea29ea6..6c977f9 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -519,6 +519,11 @@
   has_hid_event_handlers_ = has_hid_event_handlers;
 }
 
+void ServiceWorkerVersion::set_has_usb_event_handlers(
+    bool has_usb_event_handlers) {
+  has_usb_event_handlers_ = has_usb_event_handlers;
+}
+
 void ServiceWorkerVersion::StartWorker(ServiceWorkerMetrics::EventType purpose,
                                        StatusCallback callback) {
   TRACE_EVENT_INSTANT2(
@@ -1358,7 +1363,8 @@
 void ServiceWorkerVersion::OnStarted(
     blink::mojom::ServiceWorkerStartStatus start_status,
     FetchHandlerType new_fetch_handler_type,
-    bool new_has_hid_event_handlers) {
+    bool new_has_hid_event_handlers,
+    bool new_has_usb_event_handlers) {
   DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, running_status());
 
   // TODO(falken): This maps kAbruptCompletion to kErrorScriptEvaluated, which
@@ -1402,6 +1408,7 @@
     }
 
     has_hid_event_handlers_ = new_has_hid_event_handlers;
+    has_usb_event_handlers_ = new_has_usb_event_handlers;
   }
 
   // Update |sha256_script_checksum_| if it's empty. This can happen when the
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index c0eeb1b..6b353ec 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -271,6 +271,9 @@
   bool has_hid_event_handlers() const { return has_hid_event_handlers_; }
   void set_has_hid_event_handlers(bool has_hid_event_handlers);
 
+  bool has_usb_event_handlers() const { return has_usb_event_handlers_; }
+  void set_has_usb_event_handlers(bool has_usb_event_handlers);
+
   // Returns true on setup success.
   // Otherwise, setup error, and subsequent `router_evaluator()` will return
   // `absl::nullopt`.
@@ -879,7 +882,8 @@
   void OnStarting() override;
   void OnStarted(blink::mojom::ServiceWorkerStartStatus status,
                  FetchHandlerType new_fetch_handler_type,
-                 bool new_has_hid_event_handlers) override;
+                 bool new_has_hid_event_handlers,
+                 bool new_has_usb_event_handlers) override;
   void OnStopping() override;
   void OnStopped(EmbeddedWorkerStatus old_status) override;
   void OnDetached(EmbeddedWorkerStatus old_status) override;
@@ -1038,6 +1042,10 @@
   // is evaluated.
   bool has_hid_event_handlers_ = false;
 
+  // Whether the associated script has any USB event handlers after the script
+  // is evaluated.
+  bool has_usb_event_handlers_ = false;
+
   // The source of truth for navigation preload state is the
   // ServiceWorkerRegistration. |navigation_preload_state_| is essentially a
   // cached value because it must be looked up quickly and a live registration
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 80abcce..883f9eb 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -1517,6 +1517,7 @@
     host()->OnStarted(blink::mojom::ServiceWorkerStartStatus::kNormalCompletion,
                       blink::mojom::ServiceWorkerFetchHandlerType::kNoHandler,
                       /*has_hid_event_handlers=*/false,
+                      /*has_usb_event_handlers=*/false,
                       helper()->GetNextThreadId(),
                       blink::mojom::EmbeddedWorkerStartTiming::New());
   }
@@ -1994,7 +1995,8 @@
     host()->OnStarted(
         blink::mojom::ServiceWorkerStartStatus::kNormalCompletion,
         blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable,
-        has_hid_event_handlers_, helper()->GetNextThreadId(),
+        has_hid_event_handlers_, /*has_usb_event_handlers_=*/false,
+        helper()->GetNextThreadId(),
         blink::mojom::EmbeddedWorkerStartTiming::New());
   }
 
@@ -2016,5 +2018,44 @@
   EXPECT_FALSE(version_->has_hid_event_handlers());
 }
 
+// An instance client for controlling whether it has hid event handlers or not.
+class UsbEventHandlerClient : public FakeEmbeddedWorkerInstanceClient {
+ public:
+  UsbEventHandlerClient(EmbeddedWorkerTestHelper* helper,
+                        bool has_usb_event_handlers)
+      : FakeEmbeddedWorkerInstanceClient(helper),
+        has_usb_event_handlers_(has_usb_event_handlers) {}
+
+  UsbEventHandlerClient(const NoFetchHandlerClient&) = delete;
+  UsbEventHandlerClient& operator=(const NoFetchHandlerClient&) = delete;
+
+  void EvaluateScript() override {
+    host()->OnScriptEvaluationStart();
+    host()->OnStarted(
+        blink::mojom::ServiceWorkerStartStatus::kNormalCompletion,
+        blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable,
+        /*has_hid_event_handlers_=*/false, has_usb_event_handlers_,
+        helper()->GetNextThreadId(),
+        blink::mojom::EmbeddedWorkerStartTiming::New());
+  }
+
+ private:
+  bool has_usb_event_handlers_;
+};
+
+TEST_F(ServiceWorkerVersionTest, HasUsbEventHandler) {
+  helper_->AddNewPendingInstanceClient<UsbEventHandlerClient>(
+      helper_.get(), /*has_usb_event_handlers*/ true);
+  StartServiceWorker(version_.get());
+  EXPECT_TRUE(version_->has_usb_event_handlers());
+}
+
+TEST_F(ServiceWorkerVersionTest, NoUsbEventHandler) {
+  helper_->AddNewPendingInstanceClient<UsbEventHandlerClient>(
+      helper_.get(), /*has_usb_event_handlers*/ false);
+  StartServiceWorker(version_.get());
+  EXPECT_FALSE(version_->has_usb_event_handlers());
+}
+
 }  // namespace service_worker_version_unittest
 }  // namespace content
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index b8ba300f..6b23ccf 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -311,9 +311,6 @@
       network::switches::kHostResolverRules,
       network::switches::kIgnoreCertificateErrorsSPKIList,
       network::switches::kIgnoreUrlFetcherCertRequests,
-      network::switches::kIPAnonymizationProxyAllowList,
-      network::switches::kIPAnonymizationProxyPassword,
-      network::switches::kIPAnonymizationProxyServer,
       network::switches::kTestThirdPartyCookiePhaseout,
       sandbox::policy::switches::kNoSandbox,
 #if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 67a21bcf..2ba3adaf 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -529,7 +529,8 @@
 
   instance_host_->OnStarted(
       status, proxy_->FetchHandlerType(), proxy_->HasHidEventHandlers(),
-      WorkerThread::GetCurrentId(), std::move(start_timing_));
+      proxy_->HasUsbEventHandlers(), WorkerThread::GetCurrentId(),
+      std::move(start_timing_));
 
   TRACE_EVENT_NESTABLE_ASYNC_END0("ServiceWorker", "ServiceWorkerContextClient",
                                   this);
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc
index 3c4d83c5..de0ee78 100644
--- a/extensions/browser/event_router.cc
+++ b/extensions/browser/event_router.cc
@@ -143,6 +143,43 @@
   return LazyContextId(browser_context, listener->extension_id());
 }
 
+// If the event is for an extension, emit the appropriate dispatch to renderer
+// time UMA based on the background script type. Nothing will emit if
+// extension is null.
+void EmitEventDispatchToRendererTimeUMA(const Extension* extension,
+                                        base::TimeTicks dispatch_start_time) {
+  // These metrics are only relevant if the event is for an extension.
+  if (!extension) {
+    return;
+  }
+
+  const char* histogram_name = nullptr;
+  if (BackgroundInfo::HasPersistentBackgroundPage(extension)) {
+    histogram_name =
+        "Extensions.Events.DispatchToSendToRenderer."
+        "ExtensionPersistentBackgroundPage";
+  } else if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
+    histogram_name =
+        "Extensions.Events.DispatchToSendToRenderer.ExtensionEventPage";
+  } else if (BackgroundInfo::IsServiceWorkerBased(extension)) {
+    histogram_name =
+        "Extensions.Events.DispatchToSendToRenderer.ExtensionServiceWorker";
+  }
+
+  // `histogram_name` may be nullptr for extension contexts outside the
+  // background page (e.g. a content script in an options page that can also
+  // listen for events).
+  if (histogram_name) {
+    const base::TimeDelta send_to_renderer_time =
+        base::TimeTicks::Now() - dispatch_start_time;
+    base::UmaHistogramCustomMicrosecondsTimes(histogram_name,
+                                              /*sample=*/send_to_renderer_time,
+                                              /*min=*/base::Microseconds(1),
+                                              /*max=*/base::Minutes(5),
+                                              /*buckets=*/100);
+  }
+}
+
 // A global identifier used to distinguish extension events.
 base::AtomicSequenceNumber g_extension_event_id;
 
@@ -1100,6 +1137,8 @@
                            std::move(event_args_to_use), event.user_gesture,
                            std::move(filter_info));
 
+  EmitEventDispatchToRendererTimeUMA(extension, event.dispatch_start_time);
+
   if (!event.did_dispatch_callback.is_null()) {
     event.did_dispatch_callback.Run(EventTarget{extension_id, process->GetID(),
                                                 service_worker_version_id,
diff --git a/extensions/browser/extension_prefs_helper_factory.cc b/extensions/browser/extension_prefs_helper_factory.cc
index d583202..35215c8 100644
--- a/extensions/browser/extension_prefs_helper_factory.cc
+++ b/extensions/browser/extension_prefs_helper_factory.cc
@@ -34,9 +34,10 @@
 
 ExtensionPrefsHelperFactory::~ExtensionPrefsHelperFactory() = default;
 
-KeyedService* ExtensionPrefsHelperFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+ExtensionPrefsHelperFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new ExtensionPrefsHelper(
+  return std::make_unique<ExtensionPrefsHelper>(
       ExtensionPrefsFactory::GetForBrowserContext(context),
       ExtensionPrefValueMapFactory::GetForBrowserContext(context));
 }
diff --git a/extensions/browser/extension_prefs_helper_factory.h b/extensions/browser/extension_prefs_helper_factory.h
index 926618c..ba32870 100644
--- a/extensions/browser/extension_prefs_helper_factory.h
+++ b/extensions/browser/extension_prefs_helper_factory.h
@@ -25,7 +25,7 @@
   ExtensionPrefsHelperFactory();
   ~ExtensionPrefsHelperFactory() override;
 
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/extensions/browser/lazy_background_task_queue_factory.cc b/extensions/browser/lazy_background_task_queue_factory.cc
index f1ead87..3041a18 100644
--- a/extensions/browser/lazy_background_task_queue_factory.cc
+++ b/extensions/browser/lazy_background_task_queue_factory.cc
@@ -37,9 +37,10 @@
 LazyBackgroundTaskQueueFactory::~LazyBackgroundTaskQueueFactory() {
 }
 
-KeyedService* LazyBackgroundTaskQueueFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+LazyBackgroundTaskQueueFactory::BuildServiceInstanceForBrowserContext(
     BrowserContext* context) const {
-  return new LazyBackgroundTaskQueue(context);
+  return std::make_unique<LazyBackgroundTaskQueue>(context);
 }
 
 BrowserContext* LazyBackgroundTaskQueueFactory::GetBrowserContextToUse(
diff --git a/extensions/browser/lazy_background_task_queue_factory.h b/extensions/browser/lazy_background_task_queue_factory.h
index c78fa23..f69fc11 100644
--- a/extensions/browser/lazy_background_task_queue_factory.h
+++ b/extensions/browser/lazy_background_task_queue_factory.h
@@ -31,7 +31,7 @@
   ~LazyBackgroundTaskQueueFactory() override;
 
   // BrowserContextKeyedServiceFactory implementation
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc
index 041ae39..5125314 100644
--- a/extensions/browser/renderer_startup_helper.cc
+++ b/extensions/browser/renderer_startup_helper.cc
@@ -470,9 +470,10 @@
 
 RendererStartupHelperFactory::~RendererStartupHelperFactory() = default;
 
-KeyedService* RendererStartupHelperFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+RendererStartupHelperFactory::BuildServiceInstanceForBrowserContext(
     BrowserContext* context) const {
-  return new RendererStartupHelper(context);
+  return std::make_unique<RendererStartupHelper>(context);
 }
 
 BrowserContext* RendererStartupHelperFactory::GetBrowserContextToUse(
diff --git a/extensions/browser/renderer_startup_helper.h b/extensions/browser/renderer_startup_helper.h
index 8176ccc..a448b5a 100644
--- a/extensions/browser/renderer_startup_helper.h
+++ b/extensions/browser/renderer_startup_helper.h
@@ -175,7 +175,7 @@
   ~RendererStartupHelperFactory() override;
 
   // BrowserContextKeyedServiceFactory implementation:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* profile) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc b/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
index 3b44b24..2d30e88b 100644
--- a/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
@@ -155,7 +155,7 @@
     return CompoundImageBacking::CreateSharedMemory(
         &test_factory_, allow_shm_overlays, Mailbox::GenerateForSharedImage(),
         std::move(handle), buffer_format, gfx::BufferPlane::DEFAULT, size,
-        gfx::ColorSpace(), kBottomLeft_GrSurfaceOrigin, kOpaque_SkAlphaType,
+        gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kOpaque_SkAlphaType,
         SHARED_IMAGE_USAGE_DISPLAY_READ, "TestLabel");
   }
 
@@ -175,7 +175,7 @@
     return CompoundImageBacking::CreateSharedMemory(
         &test_factory_, allow_shm_overlays, Mailbox::GenerateForSharedImage(),
         std::move(handle), viz::MultiPlaneFormat::kNV12, size,
-        gfx::ColorSpace(), kBottomLeft_GrSurfaceOrigin, kOpaque_SkAlphaType,
+        gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kOpaque_SkAlphaType,
         SHARED_IMAGE_USAGE_DISPLAY_READ, "TestLabel");
   }
 
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.cc b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
index 8426958..016f68f 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
@@ -309,6 +309,12 @@
     return nullptr;
   }
 
+  if (surface_origin() != kTopLeft_GrSurfaceOrigin) {
+    LOG(ERROR)
+        << "Skia write access is only allowed for top left origin surfaces.";
+    return nullptr;
+  }
+
   std::unique_ptr<skgpu::MutableTextureState> end_state;
   if (use_sk_surface) {
     std::vector<sk_sp<SkSurface>> surfaces =
@@ -546,6 +552,12 @@
     return nullptr;
   }
 
+  if (surface_origin() != kTopLeft_GrSurfaceOrigin) {
+    LOG(ERROR)
+        << "Skia write access is only allowed for top left origin surfaces.";
+    return nullptr;
+  }
+
   if (use_sk_surface) {
     std::vector<sk_sp<SkSurface>> surfaces =
         BeginWriteAccess(surface_props, update_rect);
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index 980fdbb..0c2b481 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -16,16 +16,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 118.0.5964.0',
+    'description': 'Run with ash-chrome version 118.0.5965.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v118.0.5964.0',
-          'revision': 'version:118.0.5964.0',
+          'location': 'lacros_version_skew_tests_v118.0.5965.0',
+          'revision': 'version:118.0.5965.0',
         },
       ],
     },
@@ -372,7 +372,7 @@
     'identifier': 'BRYA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'brya',
-      'cros_img': 'brya-release/R118-15574.0.0',
+      'cros_img': 'brya-release/R118-15585.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'shards': 10,
     },
@@ -381,7 +381,7 @@
     'identifier': 'DEDEDE_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'dedede',
-      'cros_img': 'dedede-release/R118-15574.0.0',
+      'cros_img': 'dedede-release/R118-15585.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -410,7 +410,7 @@
     'identifier': 'EVE_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-release/R118-15574.0.0',
+      'cros_img': 'eve-release/R118-15585.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -439,7 +439,7 @@
     'identifier': 'EVE_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-public/R118-15574.0.0',
+      'cros_img': 'eve-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -450,7 +450,7 @@
     'identifier': 'HANA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'hana',
-      'cros_img': 'hana-release/R118-15574.0.0',
+      'cros_img': 'hana-release/R118-15585.0.0',
     },
   },
   'CROS_HANA_RELEASE_DEV': {
@@ -478,7 +478,7 @@
     'identifier': 'JACUZZI_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-release/R117-15564.0.0',
+      'cros_img': 'jacuzzi-release/R118-15585.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -500,7 +500,7 @@
     'identifier': 'JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-release/R117-15564.0.0',
+      'cros_img': 'jacuzzi-release/R118-15585.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'shards': 10,
     },
@@ -516,7 +516,7 @@
     'identifier': 'JACUZZI_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R117-15564.0.0',
+      'cros_img': 'jacuzzi-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -524,7 +524,7 @@
     'identifier': 'JACUZZI_CQ_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R117-15564.0.0',
+      'cros_img': 'jacuzzi-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
       'public_builder': 'cros_test_platform_public',
       'public_builder_bucket': 'testplatform-public',
@@ -534,7 +534,7 @@
     'identifier': 'KEVIN64_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'kevin',
-      'cros_img': 'kevin64-public/R118-15574.0.0',
+      'cros_img': 'kevin64-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -550,7 +550,7 @@
     'identifier': 'OCTOPUS_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-public/R118-15574.0.0',
+      'cros_img': 'octopus-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -558,7 +558,7 @@
     'identifier': 'OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-release/R118-15574.0.0',
+      'cros_img': 'octopus-release/R118-15585.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'shards': 10,
     },
@@ -567,7 +567,7 @@
     'identifier': 'OCTOPUS_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-release/R118-15574.0.0',
+      'cros_img': 'octopus-release/R118-15585.0.0',
     },
   },
   'CROS_OCTOPUS_RELEASE_DEV': {
@@ -633,7 +633,7 @@
     'identifier': 'VOLTEER_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'volteer',
-      'cros_img': 'volteer-public/R118-15574.0.0',
+      'cros_img': 'volteer-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -677,7 +677,7 @@
     'identifier': 'VOLTEER_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'volteer',
-      'cros_img': 'volteer-release/R118-15574.0.0',
+      'cros_img': 'volteer-release/R118-15585.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'shards': 10,
     },
diff --git a/infra/config/targets/cros-skylab-variants.json b/infra/config/targets/cros-skylab-variants.json
index 793ac53..9a689041 100644
--- a/infra/config/targets/cros-skylab-variants.json
+++ b/infra/config/targets/cros-skylab-variants.json
@@ -2,8 +2,8 @@
   "CROS_BRYA_RELEASE_ASH_LKGM": {
     "skylab": {
       "cros_board": "brya",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "brya-release/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "brya-release/R118-15585.0.0",
       "autotest_name": "tast.chrome-from-gcs",
       "shards": 10
     },
@@ -12,8 +12,8 @@
   "CROS_DEDEDE_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "dedede",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "dedede-release/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "dedede-release/R118-15585.0.0",
       "autotest_name": "tast.lacros-from-gcs"
     },
     "enabled": true,
@@ -49,8 +49,8 @@
   "CROS_EVE_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "eve",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "eve-release/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "eve-release/R118-15585.0.0",
       "autotest_name": "tast.lacros-from-gcs"
     },
     "enabled": true,
@@ -86,8 +86,8 @@
   "CROS_EVE_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "eve",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "eve-public/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "eve-public/R118-15585.0.0",
       "bucket": "chromiumos-image-archive",
       "dut_pool": "chromium",
       "public_builder": "cros_test_platform_public",
@@ -99,8 +99,8 @@
   "CROS_HANA_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "hana",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "hana-release/R118-15574.0.0"
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "hana-release/R118-15585.0.0"
     },
     "enabled": true,
     "identifier": "HANA_RELEASE_LKGM"
@@ -135,8 +135,8 @@
   "CROS_JACUZZI_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
-      "cros_chrome_version": "117.0.5922.0",
-      "cros_img": "jacuzzi-release/R117-15564.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "jacuzzi-release/R118-15585.0.0",
       "autotest_name": "tast.lacros-from-gcs"
     },
     "enabled": true,
@@ -163,8 +163,8 @@
   "CROS_JACUZZI_RELEASE_CHROME_FROM_TLS_ASH_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
-      "cros_chrome_version": "117.0.5922.0",
-      "cros_img": "jacuzzi-release/R117-15564.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "jacuzzi-release/R118-15585.0.0",
       "autotest_name": "tast.chrome-from-gcs",
       "shards": 10
     },
@@ -182,8 +182,8 @@
   "CROS_JACUZZI_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
-      "cros_chrome_version": "117.0.5922.0",
-      "cros_img": "jacuzzi-public/R117-15564.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "jacuzzi-public/R118-15585.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -192,8 +192,8 @@
   "CROS_JACUZZI_CQ_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
-      "cros_chrome_version": "117.0.5922.0",
-      "cros_img": "jacuzzi-public/R117-15564.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "jacuzzi-public/R118-15585.0.0",
       "bucket": "chromiumos-image-archive",
       "public_builder": "cros_test_platform_public",
       "public_builder_bucket": "testplatform-public"
@@ -204,8 +204,8 @@
   "CROS_KEVIN64_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "kevin",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "kevin64-public/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "kevin64-public/R118-15585.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -224,8 +224,8 @@
   "CROS_OCTOPUS_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "octopus",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "octopus-public/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "octopus-public/R118-15585.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -234,8 +234,8 @@
   "CROS_OCTOPUS_RELEASE_CHROME_FROM_TLS_ASH_LKGM": {
     "skylab": {
       "cros_board": "octopus",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "octopus-release/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "octopus-release/R118-15585.0.0",
       "autotest_name": "tast.chrome-from-gcs",
       "shards": 10
     },
@@ -244,8 +244,8 @@
   "CROS_OCTOPUS_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "octopus",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "octopus-release/R118-15574.0.0"
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "octopus-release/R118-15585.0.0"
     },
     "enabled": true,
     "identifier": "OCTOPUS_RELEASE_LKGM"
@@ -327,8 +327,8 @@
   "CROS_VOLTEER_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "volteer",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "volteer-public/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "volteer-public/R118-15585.0.0",
       "bucket": "chromiumos-image-archive",
       "dut_pool": "chromium",
       "public_builder": "cros_test_platform_public",
@@ -379,8 +379,8 @@
   "CROS_VOLTEER_RELEASE_ASH_LKGM": {
     "skylab": {
       "cros_board": "volteer",
-      "cros_chrome_version": "117.0.5936.0",
-      "cros_img": "volteer-release/R118-15574.0.0",
+      "cros_chrome_version": "118.0.5956.0",
+      "cros_img": "volteer-release/R118-15585.0.0",
       "autotest_name": "tast.chrome-from-gcs",
       "shards": 10
     },
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json
index f52c718..db3064b 100644
--- a/infra/config/targets/lacros-version-skew-variants.json
+++ b/infra/config/targets/lacros-version-skew-variants.json
@@ -1,16 +1,16 @@
 {
   "LACROS_VERSION_SKEW_CANARY": {
     "args": [
-      "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+      "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
     ],
-    "description": "Run with ash-chrome version 118.0.5964.0",
+    "description": "Run with ash-chrome version 118.0.5965.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_v118.0.5964.0",
-          "revision": "version:118.0.5964.0"
+          "location": "lacros_version_skew_tests_v118.0.5965.0",
+          "revision": "version:118.0.5965.0"
         }
       ]
     }
diff --git a/ios/chrome/browser/policy/cloud/user_policy_signin_service.mm b/ios/chrome/browser/policy/cloud/user_policy_signin_service.mm
index da465b9..b668a121 100644
--- a/ios/chrome/browser/policy/cloud/user_policy_signin_service.mm
+++ b/ios/chrome/browser/policy/cloud/user_policy_signin_service.mm
@@ -110,13 +110,6 @@
     return false;
   }
 
-  if (!browser_state_prefs_->GetBoolean(
-          policy::policy_prefs::kUserPolicyNotificationWasShown)) {
-    // Return false if the user hasn't yet seen the notification about User
-    // Policy.
-    return false;
-  }
-
   return CanApplyPoliciesForSignedInUser(check_for_refresh_token,
                                          GetConsentLevelForRegistration(),
                                          identity_manager());
diff --git a/ios/chrome/browser/policy/cloud/user_policy_signin_service_unittest.mm b/ios/chrome/browser/policy/cloud/user_policy_signin_service_unittest.mm
index 64a5bd1..a53b7b1e 100644
--- a/ios/chrome/browser/policy/cloud/user_policy_signin_service_unittest.mm
+++ b/ios/chrome/browser/policy/cloud/user_policy_signin_service_unittest.mm
@@ -129,10 +129,6 @@
         std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
     RegisterBrowserStatePrefs(prefs->registry());
 
-    // Set the User Policy notification as seen by default.
-    prefs->SetBoolean(policy::policy_prefs::kUserPolicyNotificationWasShown,
-                      true);
-
     TestChromeBrowserState::Builder builder;
     builder.SetPrefService(
         std::unique_ptr<sync_preferences::PrefServiceSyncable>(
@@ -402,33 +398,6 @@
   EXPECT_FALSE(manager_->core()->service());
 }
 
-// Tests that the user policy manager isn't initialized if the user hasn't seen
-// the User Policy notification, even if the user if the feature is enabled.
-TEST_F(UserPolicySigninServiceTest,
-       DontRegister_BecauseUserHasntSeenNotification) {
-  // Set the managed account as signed in and syncing.
-  AccountInfo account_info =
-      identity_test_env()->MakeAccountAvailable(kManagedTestUser);
-  identity_test_env()->SetPrimaryAccount(kManagedTestUser,
-                                         signin::ConsentLevel::kSync);
-
-  // Mark the store as loaded to allow registration during the initialization of
-  // the user policy service.
-  mock_store_->NotifyStoreLoaded();
-
-  // Set the User Policy notification has not seen.
-  browser_state_->GetPrefs()->SetBoolean(
-      policy::policy_prefs::kUserPolicyNotificationWasShown, false);
-
-  // Initialize the UserPolicySigninService while the user has sync enabled,
-  // but hasn't seen the notification.
-  InitUserPolicySigninService();
-
-  // Expect that the UserCloudPolicyManager isn't initialized because the user
-  // hasn't seen the notification yet.
-  EXPECT_FALSE(manager_->core()->service());
-}
-
 // Tests that the registration for user policy and the initialization of the
 // user policy manager can be done when the user is signed-in+sync and has
 // both consent levels enabled.
diff --git a/ios/chrome/browser/policy/user_policy_egtest.mm b/ios/chrome/browser/policy/user_policy_egtest.mm
index cfd0fcf..0cd11969 100644
--- a/ios/chrome/browser/policy/user_policy_egtest.mm
+++ b/ios/chrome/browser/policy/user_policy_egtest.mm
@@ -238,6 +238,8 @@
         policy::kUserPolicyForSigninAndNoSyncConsentLevel);
   } else {
     config.features_enabled.push_back(
+        policy::kUserPolicyForSigninAndNoSyncConsentLevel);
+    config.features_enabled.push_back(
         policy::kUserPolicyForSigninOrSyncConsentLevel);
   }
   return config;
@@ -326,13 +328,6 @@
 
   VerifyThatPoliciesAreSet();
 
-  // Set the notice as already shown as the show managed account dialog isn't
-  // yet part of the sign-in without sync flow.
-  [ChromeEarlGreyAppInterface
-      setBoolValue:YES
-       forUserPref:base::SysUTF8ToNSString(
-                       policy::policy_prefs::kUserPolicyNotificationWasShown)];
-
   // Restart the browser while keeping Sync ON by preserving the identity of the
   // managed account.
   AppLaunchConfiguration config = [self appConfigurationForTestCase];
@@ -426,7 +421,7 @@
       identityWithEmail:base::SysUTF8ToNSString(GetTestEmail().c_str())
                  gaiaID:@"exampleManagedID"
                    name:@"Fake Managed"];
-  [SigninEarlGreyUI signinWithFakeIdentity:fakeManagedIdentity];
+  [SigninEarlGreyUI signinWithFakeIdentity:fakeManagedIdentity enableSync:NO];
 
   // Restart the browser while keeping Sync ON by preserving the identity of the
   // managed account.
diff --git a/ios/chrome/browser/snapshots/snapshot_cache.h b/ios/chrome/browser/snapshots/snapshot_cache.h
index 85bd122d..2f5475a06 100644
--- a/ios/chrome/browser/snapshots/snapshot_cache.h
+++ b/ios/chrome/browser/snapshots/snapshot_cache.h
@@ -95,13 +95,6 @@
 // Releases alls images in grey cache.
 - (void)removeGreyCache;
 
-// Requests the grey snapshot for `snapshotID`. If the image is already loaded
-// in memory, this will immediately call back with `callback`. Otherwise, only
-// uses `callback` for the most recent caller. The callback is not guaranteed to
-// be called.
-- (void)greyImageForSnapshotID:(SnapshotID)snapshotID
-                      callback:(void (^)(UIImage*))callback;
-
 // Writes a grey copy of the snapshot for `snapshotID` to disk, but if and only
 // if a color version of the snapshot already exists in memory or on disk.
 - (void)saveGreyInBackgroundForSnapshotID:(SnapshotID)snapshotID;
@@ -124,6 +117,12 @@
 
 // Additionnal methods that should only be used for tests.
 @interface SnapshotCache (TestingAdditions)
+// Requests the grey snapshot for `snapshotID`. If the image is already loaded
+// in memory, this will immediately call back with `callback`. Otherwise, only
+// uses `callback` for the most recent caller. The callback is not guaranteed to
+// be called.
+- (void)greyImageForSnapshotID:(SnapshotID)snapshotID
+                      callback:(void (^)(UIImage*))callback;
 - (BOOL)hasImageInMemory:(SnapshotID)snapshotID;
 - (BOOL)hasGreyImageInMemory:(SnapshotID)snapshotID;
 - (NSUInteger)lruCacheMaxSize;
diff --git a/ios/chrome/browser/snapshots/snapshot_cache.mm b/ios/chrome/browser/snapshots/snapshot_cache.mm
index fe8a9f9..f1a5b6a 100644
--- a/ios/chrome/browser/snapshots/snapshot_cache.mm
+++ b/ios/chrome/browser/snapshots/snapshot_cache.mm
@@ -747,22 +747,6 @@
   _mostRecentGreyBlock = nil;
 }
 
-- (void)greyImageForSnapshotID:(SnapshotID)snapshotID
-                      callback:(void (^)(UIImage*))callback {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
-  DCHECK(snapshotID.valid());
-  DCHECK(callback);
-
-  auto iterator = _greyImageDictionary.find(snapshotID);
-  if (iterator != _greyImageDictionary.end()) {
-    callback(iterator->second);
-    [self clearGreySnapshotInfo];
-  } else {
-    _mostRecentGreySnapshotID = snapshotID;
-    _mostRecentGreyBlock = [callback copy];
-  }
-}
-
 - (void)retrieveGreyImageForSnapshotID:(SnapshotID)snapshotID
                               callback:(void (^)(UIImage*))callback {
   DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
@@ -844,6 +828,22 @@
 
 @implementation SnapshotCache (TestingAdditions)
 
+- (void)greyImageForSnapshotID:(SnapshotID)snapshotID
+                      callback:(void (^)(UIImage*))callback {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(_sequenceChecker);
+  DCHECK(snapshotID.valid());
+  DCHECK(callback);
+
+  auto iterator = _greyImageDictionary.find(snapshotID);
+  if (iterator != _greyImageDictionary.end()) {
+    callback(iterator->second);
+    [self clearGreySnapshotInfo];
+  } else {
+    _mostRecentGreySnapshotID = snapshotID;
+    _mostRecentGreyBlock = [callback copy];
+  }
+}
+
 - (BOOL)hasImageInMemory:(SnapshotID)snapshotID {
   return [_lruCache objectForKey:snapshotID] != nil;
 }
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
index 6cc9adc..58364b2 100644
--- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -212,6 +212,7 @@
     "//ios/chrome/browser/ntp",
     "//ios/chrome/browser/ntp:set_up_list",
     "//ios/chrome/browser/ntp:set_up_list_item_type",
+    "//ios/chrome/browser/passwords:password_checkup_utils",
     "//ios/chrome/browser/safety_check:constants",
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/shared/public/features",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
index 2781b27..35d8ee1 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
@@ -60,6 +60,7 @@
     "//ui/base",
     "//url",
   ]
+  frameworks = [ "UIKit.framework" ]
 }
 
 source_set("constants") {
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container.mm b/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container.mm
index 0666f8a1..75ed1c64 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container.mm
@@ -57,6 +57,7 @@
   NSLayoutConstraint* _contentViewWidthAnchor;
   id<MagicStackModuleContainerDelegate> _delegate;
   UILabel* _title;
+  UILabel* _subtitle;
 }
 
 - (instancetype)initWithType:(ContentSuggestionsModuleType)type {
@@ -133,6 +134,24 @@
           setContentHuggingPriority:UILayoutPriorityDefaultHigh
                             forAxis:UILayoutConstraintAxisHorizontal];
       [titleStackView addArrangedSubview:showMoreButton];
+    } else if ([self shouldShowSubtitle]) {
+      // TODO(crbug.com/1474992): Update MagicStackModuleContainer to take an id
+      // config in its initializer so the container can build itself from a
+      // passed config/state object.
+      NSString* subtitle = [delegate subtitleStringForModule:type];
+
+      _subtitle = [[UILabel alloc] init];
+      _subtitle.text = subtitle;
+      _subtitle.font = [MagicStackModuleContainer fontForSubtitle];
+      _subtitle.textColor = [UIColor colorNamed:kTextSecondaryColor];
+      _subtitle.numberOfLines = 0;
+      _subtitle.lineBreakMode = NSLineBreakByWordWrapping;
+      _subtitle.accessibilityTraits |= UIAccessibilityTraitHeader;
+      _subtitle.accessibilityIdentifier = subtitle;
+      [_subtitle setContentHuggingPriority:UILayoutPriorityDefaultHigh
+                                   forAxis:UILayoutConstraintAxisHorizontal];
+
+      [titleStackView addArrangedSubview:_subtitle];
     }
 
     UIStackView* stackView = [[UIStackView alloc] init];
@@ -237,6 +256,10 @@
   return CreateDynamicFont(UIFontTextStyleFootnote, UIFontWeightSemibold);
 }
 
++ (UIFont*)fontForSubtitle {
+  return CreateDynamicFont(UIFontTextStyleFootnote, UIFontWeightRegular);
+}
+
 - (NSDirectionalEdgeInsets)contentMargins {
   NSDirectionalEdgeInsets contentMargins =
       NSDirectionalEdgeInsetsMake(kContentTopInset, kContentHorizontalInset,
@@ -341,6 +364,16 @@
   }
 }
 
+- (BOOL)shouldShowSubtitle {
+  switch (_type) {
+    case ContentSuggestionsModuleType::kSafetyCheck:
+    case ContentSuggestionsModuleType::kSafetyCheckMultiRow:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
 - (BOOL)shouldShowSeeMore {
   switch (_type) {
     case ContentSuggestionsModuleType::kCompactedSetUpList:
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container_delegate.h b/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container_delegate.h
index ecb98e3..924aef8c 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container_delegate.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/magic_stack_module_container_delegate.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_MAGIC_STACK_MODULE_CONTAINER_DELEGATE_H_
 #define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_MAGIC_STACK_MODULE_CONTAINER_DELEGATE_H_
 
+#import <UIKit/UIKit.h>
+
 enum class ContentSuggestionsModuleType;
 
 // Protocol asking the receiver for more contextual information about modules.
@@ -22,6 +24,9 @@
 // anymore.
 - (void)neverShowModuleType:(ContentSuggestionsModuleType)type;
 
+// Returns the subtitle string for the module `type`.
+- (NSString*)subtitleStringForModule:(ContentSuggestionsModuleType)type;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_MAGIC_STACK_MODULE_CONTAINER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
index c697202..9919823 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -325,6 +325,8 @@
                   safeBrowsingState:initialSafeBrowsingState
                        runningState:initialRunningState];
 
+      _safetyCheckState.lastRunTime = lastRunTime;
+
       std::vector<password_manager::CredentialUIEntry> insecureCredentials =
           safetyCheckManager->GetInsecureCredentials();
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index ef8b104d..d95e7a1 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -7,11 +7,13 @@
 #import "base/apple/foundation_util.h"
 #import "base/metrics/user_metrics.h"
 #import "base/metrics/user_metrics_action.h"
+#import "base/time/time.h"
 #import "components/segmentation_platform/public/features.h"
 #import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/drag_and_drop/url_drag_drop_handler.h"
 #import "ios/chrome/browser/ntp/set_up_list_item.h"
 #import "ios/chrome/browser/ntp/set_up_list_item_type.h"
+#import "ios/chrome/browser/passwords/password_checkup_utils.h"
 #import "ios/chrome/browser/safety_check/ios_chrome_safety_check_manager_constants.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
@@ -53,6 +55,7 @@
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/favicon/favicon_view.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
+#import "third_party/abseil-cpp/absl/types/optional.h"
 #import "ui/base/device_form_factor.h"
 #import "ui/base/l10n/l10n_util.h"
 #import "url/gurl.h"
@@ -851,6 +854,18 @@
   [self.audience neverShowModuleType:type];
 }
 
+- (NSString*)subtitleStringForModule:(ContentSuggestionsModuleType)type {
+  if (type == ContentSuggestionsModuleType::kSafetyCheck ||
+      type == ContentSuggestionsModuleType::kSafetyCheckMultiRow) {
+    absl::optional<base::Time> lastRunTime =
+        absl::optional<base::Time>(_safetyCheckState.lastRunTime);
+
+    return password_manager::FormatElapsedTimeSinceLastCheck(lastRunTime);
+  }
+
+  return @"";
+}
+
 #pragma mark - Private
 
 - (void)addUIElement:(UIView*)view withCustomBottomSpacing:(CGFloat)spacing {
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
index c1d451e..99e59b1 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -124,6 +124,8 @@
   // Mark What's New as already-seen so it does not override Bookmarks.
   [ChromeEarlGrey setUserDefaultObject:@YES
                                 forKey:@"userHasInteractedWithWhatsNew"];
+  [ChromeEarlGrey setUserDefaultObject:@YES
+                                forKey:@"userHasInteractedWithWhatsNewM116"];
   [NTPHomeTestCase setUpHelper];
 }
 
@@ -141,6 +143,8 @@
   // Clean up What's New already-seen.
   [ChromeEarlGrey
       removeUserDefaultObjectForKey:@"userHasInteractedWithWhatsNew"];
+  [ChromeEarlGrey setUserDefaultObject:@YES
+                                forKey:@"userHasInteractedWithWhatsNewM116"];
 
   [super tearDown];
 }
@@ -249,6 +253,68 @@
       performAction:grey_tap()];
 }
 
+// Tests that the collections shortcut are displayed and working.
+- (void)testCollectionShortcutsWithWhatsNew {
+  AppLaunchConfiguration config = self.appConfigurationForTestCase;
+  config.relaunch_policy = ForceRelaunchByCleanShutdown;
+  [ChromeEarlGrey setUserDefaultObject:@NO
+                                forKey:@"userHasInteractedWithWhatsNewM116"];
+
+  [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+
+  // Check the What's New.
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_IOS_CONTENT_SUGGESTIONS_WHATS_NEW)]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:
+                 chrome_test_util::NavigationBarTitleWithAccessibilityLabelId(
+                     IDS_IOS_CONTENT_SUGGESTIONS_WHATS_NEW)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()]
+      performAction:grey_tap()];
+
+  // Check the ReadingList.
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_IOS_CONTENT_SUGGESTIONS_READING_LIST)]
+      performAction:grey_tap()];
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::HeaderWithAccessibilityLabelId(
+                                   IDS_IOS_TOOLS_MENU_READING_LIST)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()]
+      performAction:grey_tap()];
+
+  // Check the RecentTabs.
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_IOS_CONTENT_SUGGESTIONS_RECENT_TABS)]
+      performAction:grey_tap()];
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::HeaderWithAccessibilityLabelId(
+                                   IDS_IOS_CONTENT_SUGGESTIONS_RECENT_TABS)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()]
+      performAction:grey_tap()];
+
+  // Check the History.
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
+                                   IDS_IOS_CONTENT_SUGGESTIONS_HISTORY)]
+      performAction:grey_tap()];
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::HeaderWithAccessibilityLabelId(
+                                   IDS_HISTORY_TITLE)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()]
+      performAction:grey_tap()];
+}
+
 // Tests that when loading an invalid URL, the NTP is still displayed.
 // Prevents regressions from https://crbug.com/1063154 .
 - (void)testInvalidURL {
diff --git a/ios/chrome/browser/ui/content_suggestions/safety_check/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/safety_check/BUILD.gn
index 0e357b9..a4c82c1 100644
--- a/ios/chrome/browser/ui/content_suggestions/safety_check/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/safety_check/BUILD.gn
@@ -16,9 +16,9 @@
     "utils.h",
     "utils.mm",
   ]
+  public_deps = [ "//base" ]
   deps = [
     ":constants",
-    "//base",
     "//components/password_manager/core/browser",
     "//components/password_manager/core/common:features",
     "//components/version_info",
diff --git a/ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_state.h b/ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_state.h
index 5722a58..5cec1fc3 100644
--- a/ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_state.h
+++ b/ios/chrome/browser/ui/content_suggestions/safety_check/safety_check_state.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SAFETY_CHECK_SAFETY_CHECK_STATE_H_
 #define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SAFETY_CHECK_SAFETY_CHECK_STATE_H_
 
+#import "base/time/time.h"
+
 #import <UIKit/UIKit.h>
 
 enum class UpdateChromeSafetyCheckState;
@@ -44,6 +46,9 @@
 // The number of compromised passwords found by the Password check.
 @property(nonatomic, assign) NSInteger compromisedPasswordsCount;
 
+// The last run time of the Safety Check.
+@property(nonatomic, assign) base::Time lastRunTime;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SAFETY_CHECK_SAFETY_CHECK_STATE_H_
diff --git a/media/filters/manifest_demuxer_unittest.cc b/media/filters/manifest_demuxer_unittest.cc
index 5d11d60f..ef8274b25 100644
--- a/media/filters/manifest_demuxer_unittest.cc
+++ b/media/filters/manifest_demuxer_unittest.cc
@@ -64,6 +64,8 @@
   ~ManifestDemuxerTest() override {
     manifest_demuxer_->GetChunkDemuxerForTesting()->MarkEndOfStream(
         PIPELINE_OK);
+    // Reset pointer so that it does not dangle.
+    mock_engine_ = nullptr;
     manifest_demuxer_.reset();
     base::RunLoop().RunUntilIdle();
   }
@@ -74,7 +76,7 @@
 
   void CreateIdAndAppendInitSegment(const std::string& id) {
     auto* demuxer = manifest_demuxer_->GetChunkDemuxerForTesting();
-    DCHECK_EQ(demuxer->AddId(id, "video/webm", "vorbis,vp8"),
+    ASSERT_EQ(demuxer->AddId(id, "video/webm", "vorbis,vp8"),
               ChunkDemuxer::Status::kOk);
 
     demuxer->SetTracksWatcher(
@@ -83,12 +85,13 @@
         id, base::BindRepeating([](SourceBufferParseWarning) {}));
 
     scoped_refptr<DecoderBuffer> bear1 = ReadTestDataFile("bear-320x240.webm");
-    DCHECK(demuxer->AppendToParseBuffer(id, bear1->data(), bear1->data_size()));
+    ASSERT_TRUE(
+        demuxer->AppendToParseBuffer(id, bear1->data(), bear1->data_size()));
     for (;;) {
       base::TimeDelta start = base::Seconds(0), end = base::Seconds(10), offset;
       auto result = demuxer->RunSegmentParserLoop(id, start, end, &offset);
       if (result != StreamParser::ParseStatus::kSuccessHasMoreData) {
-        DCHECK_EQ(result, StreamParser::ParseStatus::kSuccess);
+        ASSERT_EQ(result, StreamParser::ParseStatus::kSuccess);
         return;
       }
     }
diff --git a/media/gpu/windows/d3d11_decoder_configurator.cc b/media/gpu/windows/d3d11_decoder_configurator.cc
index 3150010..9363bab 100644
--- a/media/gpu/windows/d3d11_decoder_configurator.cc
+++ b/media/gpu/windows/d3d11_decoder_configurator.cc
@@ -13,7 +13,6 @@
 #include "media/base/media_switches.h"
 #include "media/base/win/mf_helpers.h"
 #include "media/gpu/windows/av1_guids.h"
-#include "media/gpu/windows/d3d11_copying_texture_wrapper.h"
 #include "media/gpu/windows/d3d11_status.h"
 #include "media/gpu/windows/supported_profile_helpers.h"
 #include "ui/gfx/geometry/size.h"
@@ -21,6 +20,50 @@
 
 namespace media {
 
+namespace {
+
+GUID GetD3D11DecoderGUID(const VideoCodecProfile& profile,
+                         uint8_t bit_depth,
+                         VideoChromaSampling chroma_sampling) {
+  switch (profile) {
+    case H264PROFILE_BASELINE:
+    case H264PROFILE_MAIN:
+    case H264PROFILE_EXTENDED:
+    case H264PROFILE_HIGH:
+    case H264PROFILE_HIGH10PROFILE:
+    case H264PROFILE_HIGH422PROFILE:
+    case H264PROFILE_HIGH444PREDICTIVEPROFILE:
+    case H264PROFILE_SCALABLEBASELINE:
+    case H264PROFILE_SCALABLEHIGH:
+    case H264PROFILE_STEREOHIGH:
+    case H264PROFILE_MULTIVIEWHIGH:
+      return D3D11_DECODER_PROFILE_H264_VLD_NOFGT;
+    case VP9PROFILE_PROFILE0:
+      return D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0;
+    case VP9PROFILE_PROFILE2:
+      return D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2;
+    case AV1PROFILE_PROFILE_MAIN:
+      return DXVA_ModeAV1_VLD_Profile0;
+    case AV1PROFILE_PROFILE_HIGH:
+      return DXVA_ModeAV1_VLD_Profile1;
+    case AV1PROFILE_PROFILE_PRO:
+      return DXVA_ModeAV1_VLD_Profile2;
+#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
+    case HEVCPROFILE_MAIN:
+      return D3D11_DECODER_PROFILE_HEVC_VLD_MAIN;
+    case HEVCPROFILE_MAIN10:
+      return D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10;
+    case HEVCPROFILE_REXT:
+      return GetHEVCRangeExtensionPrivateGUID(bit_depth, chroma_sampling);
+#endif  // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
+    default:
+      return {};
+  }
+  NOTREACHED_NORETURN();
+}
+
+}  // namespace
+
 D3D11DecoderConfigurator::D3D11DecoderConfigurator(
     DXGI_FORMAT decoder_output_dxgifmt,
     GUID decoder_guid,
@@ -50,93 +93,37 @@
   const bool supports_nv12_decode_swap_chain =
       gl::DirectCompositionDecodeSwapChainSupported() && !use_shared_handle;
 
-  DXGI_FORMAT decoder_dxgi_format = DXGI_FORMAT_UNKNOWN;
-  // Assume YUV420 format.
-  switch (bit_depth) {
-    case 8:
-      decoder_dxgi_format = DXGI_FORMAT_NV12;
-      break;
-    case 10:
-      decoder_dxgi_format = DXGI_FORMAT_P010;
-      break;
-    case 12:
-      decoder_dxgi_format = DXGI_FORMAT_P016;
-      break;
-    default:
-      MEDIA_LOG(WARNING, media_log)
-          << "D3D11VideoDecoder does not support bit depth "
-          << base::strict_cast<int>(bit_depth);
-      return nullptr;
+  DXGI_FORMAT decoder_dxgi_format =
+      GetOutputDXGIFormat(bit_depth, chroma_sampling);
+  if (decoder_dxgi_format == DXGI_FORMAT_UNKNOWN) {
+    MEDIA_LOG(WARNING, media_log)
+        << "D3D11VideoDecoder does not support bit depth "
+        << base::strict_cast<int>(bit_depth)
+        << " with chroma subsampling format "
+        << VideoChromaSamplingToString(chroma_sampling);
+    return nullptr;
   }
 
-  GUID decoder_guid = {};
-  if (config.codec() == VideoCodec::kH264) {
-    decoder_guid = D3D11_DECODER_PROFILE_H264_VLD_NOFGT;
-  } else if (config.profile() == VP9PROFILE_PROFILE0) {
-    decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0;
-  } else if (config.profile() == VP9PROFILE_PROFILE2) {
-    decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2;
-  } else if (config.profile() == AV1PROFILE_PROFILE_MAIN) {
-    decoder_guid = DXVA_ModeAV1_VLD_Profile0;
-  } else if (config.profile() == AV1PROFILE_PROFILE_HIGH) {
-    decoder_guid = DXVA_ModeAV1_VLD_Profile1;
-  } else if (config.profile() == AV1PROFILE_PROFILE_PRO) {
-    decoder_guid = DXVA_ModeAV1_VLD_Profile2;
-  }
+  GUID decoder_guid =
+      GetD3D11DecoderGUID(config.profile(), bit_depth, chroma_sampling);
 #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
-  else if (config.profile() == HEVCPROFILE_MAIN) {
-    decoder_guid = D3D11_DECODER_PROFILE_HEVC_VLD_MAIN;
-  } else if (config.profile() == HEVCPROFILE_MAIN10) {
-    decoder_guid = D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10;
-  } else if (config.profile() == HEVCPROFILE_REXT) {
-    if (bit_depth == 8) {
-      if (chroma_sampling == VideoChromaSampling::k420) {
-        decoder_guid = DXVA_ModeHEVC_VLD_Main_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_NV12;
-      } else if (chroma_sampling == VideoChromaSampling::k422) {
-        // For D3D11/D3D12, 8b/10b-422 HEVC will share 10b-422 GUID no matter
-        // it is defined by Intel or DXVA spec(as part of Windows SDK).
-        decoder_guid = DXVA_ModeHEVC_VLD_Main422_10_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_Y210;
-      } else if (chroma_sampling == VideoChromaSampling::k444) {
-        decoder_guid = DXVA_ModeHEVC_VLD_Main444_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_AYUV;
-      } else {
-        MEDIA_LOG(INFO, media_log)
-            << "D3D11VideoDecoder does not support HEVC range extension "
-            << config.codec() << " with chroma subsampling format "
-            << VideoChromaSamplingToString(chroma_sampling) << " and bit depth "
-            << base::strict_cast<int>(bit_depth);
-        return nullptr;
-      }
-    } else if (bit_depth == 10) {
-      if (chroma_sampling == VideoChromaSampling::k420) {
-        decoder_guid = DXVA_ModeHEVC_VLD_Main10_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_P010;
-      } else if (chroma_sampling == VideoChromaSampling::k422) {
-        decoder_guid = DXVA_ModeHEVC_VLD_Main422_10_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_Y210;
-      } else if (chroma_sampling == VideoChromaSampling::k444) {
-        decoder_guid = DXVA_ModeHEVC_VLD_Main444_10_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_Y410;
-      }
-    } else if (bit_depth == 12) {
-      if (chroma_sampling == VideoChromaSampling::k420) {
-        decoder_guid = DXVA_ModeHEVC_VLD_Main12_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_P016;
-      } else if (chroma_sampling == VideoChromaSampling::k422) {
-        decoder_guid = DXVA_ModeHEVC_VLD_Main422_12_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_Y216;
-      } else if (chroma_sampling == VideoChromaSampling::k444) {
-        decoder_guid = DXVA_ModeHEVC_VLD_Main444_12_Intel;
-        decoder_dxgi_format = DXGI_FORMAT_Y416;
-      }
-    }
+  // For D3D11/D3D12, 8b/10b-422 HEVC will share 10b-422 GUID no matter
+  // it is defined by Intel or DXVA spec(as part of Windows SDK).
+  if (decoder_guid == DXVA_ModeHEVC_VLD_Main422_10_Intel) {
+    decoder_dxgi_format = DXGI_FORMAT_Y210;
   }
 #endif  // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
-  else {
-    MEDIA_LOG(INFO, media_log)
-        << "D3D11VideoDecoder does not support codec " << config.codec();
+  if (decoder_guid == GUID()) {
+    if (config.profile() == HEVCPROFILE_REXT) {
+      MEDIA_LOG(INFO, media_log)
+          << "D3D11VideoDecoder does not support HEVC range extension "
+          << config.codec() << " with chroma subsampling format "
+          << VideoChromaSamplingToString(chroma_sampling) << " and bit depth "
+          << base::strict_cast<int>(bit_depth);
+    } else {
+      MEDIA_LOG(INFO, media_log)
+          << "D3D11VideoDecoder does not support codec " << config.codec();
+    }
     return nullptr;
   }
 
diff --git a/media/gpu/windows/supported_profile_helpers.cc b/media/gpu/windows/supported_profile_helpers.cc
index fc08fb7..de0e9260 100644
--- a/media/gpu/windows/supported_profile_helpers.cc
+++ b/media/gpu/windows/supported_profile_helpers.cc
@@ -97,6 +97,71 @@
 
 namespace media {
 
+#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
+GUID GetHEVCRangeExtensionPrivateGUID(uint8_t bitdepth,
+                                      VideoChromaSampling chroma_sampling) {
+  if (bitdepth == 8) {
+    if (chroma_sampling == VideoChromaSampling::k420) {
+      return DXVA_ModeHEVC_VLD_Main_Intel;
+    } else if (chroma_sampling == VideoChromaSampling::k422) {
+      // For D3D11/D3D12, 8b/10b-422 HEVC will share 10b-422 GUID no matter
+      // it is defined by Intel or DXVA spec(as part of Windows SDK).
+      return DXVA_ModeHEVC_VLD_Main422_10_Intel;
+    } else if (chroma_sampling == VideoChromaSampling::k444) {
+      return DXVA_ModeHEVC_VLD_Main444_Intel;
+    }
+
+  } else if (bitdepth == 10) {
+    if (chroma_sampling == VideoChromaSampling::k420) {
+      return DXVA_ModeHEVC_VLD_Main10_Intel;
+    } else if (chroma_sampling == VideoChromaSampling::k422) {
+      return DXVA_ModeHEVC_VLD_Main422_10_Intel;
+    } else if (chroma_sampling == VideoChromaSampling::k444) {
+      return DXVA_ModeHEVC_VLD_Main444_10_Intel;
+    }
+  } else if (bitdepth == 12) {
+    if (chroma_sampling == VideoChromaSampling::k420) {
+      return DXVA_ModeHEVC_VLD_Main12_Intel;
+    } else if (chroma_sampling == VideoChromaSampling::k422) {
+      return DXVA_ModeHEVC_VLD_Main422_12_Intel;
+    } else if (chroma_sampling == VideoChromaSampling::k444) {
+      return DXVA_ModeHEVC_VLD_Main444_12_Intel;
+    }
+  }
+  return {};
+}
+#endif  // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
+
+DXGI_FORMAT GetOutputDXGIFormat(uint8_t bitdepth,
+                                VideoChromaSampling chroma_sampling) {
+  if (bitdepth == 8) {
+    if (chroma_sampling == VideoChromaSampling::k420) {
+      return DXGI_FORMAT_NV12;
+    } else if (chroma_sampling == VideoChromaSampling::k422) {
+      return DXGI_FORMAT_YUY2;
+    } else if (chroma_sampling == VideoChromaSampling::k444) {
+      return DXGI_FORMAT_AYUV;
+    }
+  } else if (bitdepth == 10) {
+    if (chroma_sampling == VideoChromaSampling::k420) {
+      return DXGI_FORMAT_P010;
+    } else if (chroma_sampling == VideoChromaSampling::k422) {
+      return DXGI_FORMAT_Y210;
+    } else if (chroma_sampling == VideoChromaSampling::k444) {
+      return DXGI_FORMAT_Y410;
+    }
+  } else if (bitdepth == 12 || bitdepth == 16) {
+    if (chroma_sampling == VideoChromaSampling::k420) {
+      return DXGI_FORMAT_P016;
+    } else if (chroma_sampling == VideoChromaSampling::k422) {
+      return DXGI_FORMAT_Y216;
+    } else if (chroma_sampling == VideoChromaSampling::k444) {
+      return DXGI_FORMAT_Y416;
+    }
+  }
+  return {};
+}
+
 SupportedResolutionRangeMap GetSupportedD3D11VideoDecoderResolutions(
     ComD3D11Device device,
     const gpu::GpuDriverBugWorkarounds& workarounds) {
diff --git a/media/gpu/windows/supported_profile_helpers.h b/media/gpu/windows/supported_profile_helpers.h
index 2dd3f019..bd7f942d 100644
--- a/media/gpu/windows/supported_profile_helpers.h
+++ b/media/gpu/windows/supported_profile_helpers.h
@@ -10,6 +10,7 @@
 #include "base/containers/flat_map.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "media/base/video_codecs.h"
+#include "media/base/video_types.h"
 #include "media/gpu/media_gpu_export.h"
 #include "media/gpu/windows/d3d11_com_defs.h"
 #include "ui/gfx/geometry/size.h"
@@ -115,8 +116,18 @@
             0xb2,
             0xc1,
             0x97);
+
+// Get the private GUID for HEVC range extension profile supported by Intel.
+MEDIA_GPU_EXPORT GUID
+GetHEVCRangeExtensionPrivateGUID(uint8_t bitdepth,
+                                 VideoChromaSampling chroma_sampling);
 #endif  // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
 
+// Get the DXGI_FORMAT for the video decoder output texture, according to the
+// bit depth and chroma sampling format.
+MEDIA_GPU_EXPORT DXGI_FORMAT
+GetOutputDXGIFormat(uint8_t bitdepth, VideoChromaSampling chroma_sampling);
+
 struct SupportedResolutionRange {
   gfx::Size min_resolution;
   gfx::Size max_landscape_resolution;
diff --git a/media/media_options.gni b/media/media_options.gni
index 04bc278..61d5046 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -105,7 +105,7 @@
   enable_media_drm_storage = is_android || is_castos
 
   # Enable HLS manifest parser and demuxer.
-  enable_hls_demuxer = false
+  enable_hls_demuxer = proprietary_codecs && is_android
 
   # Enable inclusion of the HEVC/H265 parser and also enable HEVC/H265 decoding
   # with hardware acceleration assist. Enabled by default for fuzzer builds,
diff --git a/media/mojo/clients/mojo_video_encoder_metrics_provider.cc b/media/mojo/clients/mojo_video_encoder_metrics_provider.cc
index c95fbdff..17a549fd 100644
--- a/media/mojo/clients/mojo_video_encoder_metrics_provider.cc
+++ b/media/mojo/clients/mojo_video_encoder_metrics_provider.cc
@@ -17,13 +17,17 @@
  public:
   MojoVideoEncoderMetricsProvider(
       mojom::VideoEncoderUseCase use_case,
-      mojo::PendingRemote<mojom::VideoEncoderMetricsProvider> pending_remote)
-      : use_case_(use_case), pending_remote_(std::move(pending_remote)) {
+      mojo::PendingRemote<mojom::VideoEncoderMetricsProvider> pending_remote,
+      uint64_t encoder_id)
+      : use_case_(use_case),
+        encoder_id_(encoder_id),
+        pending_remote_(std::move(pending_remote)) {
     DETACH_FROM_SEQUENCE(sequence_checker_);
   }
 
   ~MojoVideoEncoderMetricsProvider() override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    Complete();
   }
 
   void Initialize(VideoCodecProfile codec_profile,
@@ -36,7 +40,7 @@
     }
     initialized_ = true;
     num_encoded_frames_ = 0;
-    remote_->Initialize(use_case_, codec_profile, encode_size,
+    remote_->Initialize(encoder_id_, use_case_, codec_profile, encode_size,
                         is_hardware_encoder, svc_mode);
   }
 
@@ -53,7 +57,7 @@
     // as it is important to represent whether the encoding actually starts.
     if (num_encoded_frames_ % kEncodedFrameCountBucketSize == 0 ||
         num_encoded_frames_ == 1u) {
-      remote_->SetEncodedFrameCount(num_encoded_frames_);
+      remote_->SetEncodedFrameCount(encoder_id_, num_encoded_frames_);
     }
   }
 
@@ -64,12 +68,21 @@
       return;
     }
     CHECK(!status.is_ok());
-    remote_->SetError(status);
+    remote_->SetError(encoder_id_, status);
   }
 
  private:
+  void Complete() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    if (initialized_) {
+      remote_->Complete(encoder_id_);
+    }
+    remote_.reset();
+  }
+
   const mojom::VideoEncoderUseCase use_case_
       GUARDED_BY_CONTEXT(sequence_checker_);
+  const uint64_t encoder_id_ GUARDED_BY_CONTEXT(sequence_checker_);
 
   mojo::PendingRemote<mojom::VideoEncoderMetricsProvider> pending_remote_;
   mojo::Remote<mojom::VideoEncoderMetricsProvider> remote_
@@ -87,6 +100,6 @@
     mojom::VideoEncoderUseCase use_case,
     mojo::PendingRemote<mojom::VideoEncoderMetricsProvider> pending_remote) {
   return std::make_unique<MojoVideoEncoderMetricsProvider>(
-      use_case, std::move(pending_remote));
+      use_case, std::move(pending_remote), /*encoder_id=*/0u);
 }
 }  // namespace media
diff --git a/media/mojo/clients/mojo_video_encoder_metrics_provider_unittest.cc b/media/mojo/clients/mojo_video_encoder_metrics_provider_unittest.cc
index 2b9b7fd4..6c0bb28 100644
--- a/media/mojo/clients/mojo_video_encoder_metrics_provider_unittest.cc
+++ b/media/mojo/clients/mojo_video_encoder_metrics_provider_unittest.cc
@@ -16,6 +16,8 @@
 
 namespace media {
 
+constexpr uint64_t kEncoderId = 0u;
+
 class MockMojomVideoEncoderMetricsProvider
     : public mojom::VideoEncoderMetricsProvider {
  public:
@@ -24,14 +26,19 @@
   // mojom::VideoEncoderMetricsProvider implementation.
   MOCK_METHOD(void,
               Initialize,
-              (mojom::VideoEncoderUseCase,
+              (uint64_t,
+               mojom::VideoEncoderUseCase,
                VideoCodecProfile,
                const gfx::Size&,
                bool,
                SVCScalabilityMode),
               (override));
-  MOCK_METHOD(void, SetEncodedFrameCount, (uint64_t), (override));
-  MOCK_METHOD(void, SetError, (const media::EncoderStatus&), (override));
+  MOCK_METHOD(void, SetEncodedFrameCount, (uint64_t, uint64_t), (override));
+  MOCK_METHOD(void,
+              SetError,
+              (uint64_t, const media::EncoderStatus&),
+              (override));
+  MOCK_METHOD(void, Complete, (uint64_t), (override));
 };
 
 class MojoVideoEncoderMetricsProviderTest : public ::testing::Test {
@@ -83,10 +90,12 @@
 
   InSequence s;
   EXPECT_CALL(*mock_mojo_receiver(),
-              Initialize(kUseCase, kCodecProfile, kEncodeSize,
+              Initialize(kEncoderId, kUseCase, kCodecProfile, kEncodeSize,
                          kIsHardwareEncoder, kSVCMode));
   mojo_encoder_metrics_provider_->Initialize(kCodecProfile, kEncodeSize,
                                              kIsHardwareEncoder, kSVCMode);
+  EXPECT_CALL(*mock_mojo_receiver(), Complete(kEncoderId));
+  mojo_encoder_metrics_provider_.reset();
   base::RunLoop().RunUntilIdle();
 }
 
@@ -99,26 +108,26 @@
 
   InSequence s;
   EXPECT_CALL(*mock_mojo_receiver(),
-              Initialize(kUseCase, kCodecProfile, kEncodeSize,
+              Initialize(kEncoderId, kUseCase, kCodecProfile, kEncodeSize,
                          kIsHardwareEncoder, kSVCMode));
   mojo_encoder_metrics_provider_->Initialize(kCodecProfile, kEncodeSize,
                                              kIsHardwareEncoder, kSVCMode);
   base::RunLoop().RunUntilIdle();
-  EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(1u));
+  EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(kEncoderId, 1u));
   mojo_encoder_metrics_provider_->IncrementEncodedFrameCount();
   base::RunLoop().RunUntilIdle();
   for (size_t i = 0; i < 98; i++) {
     mojo_encoder_metrics_provider_->IncrementEncodedFrameCount();
   }
   base::RunLoop().RunUntilIdle();
-  EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(100u));
+  EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(kEncoderId, 100u));
   mojo_encoder_metrics_provider_->IncrementEncodedFrameCount();
   base::RunLoop().RunUntilIdle();
   for (size_t i = 0; i < 99; i++) {
     mojo_encoder_metrics_provider_->IncrementEncodedFrameCount();
   }
   base::RunLoop().RunUntilIdle();
-  EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(200u));
+  EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(kEncoderId, 200u));
   mojo_encoder_metrics_provider_->IncrementEncodedFrameCount();
   base::RunLoop().RunUntilIdle();
 }
@@ -132,12 +141,12 @@
 
   InSequence s;
   EXPECT_CALL(*mock_mojo_receiver(),
-              Initialize(kUseCase, kCodecProfile, kEncodeSize,
+              Initialize(kEncoderId, kUseCase, kCodecProfile, kEncodeSize,
                          kIsHardwareEncoder, kSVCMode));
   mojo_encoder_metrics_provider_->Initialize(kCodecProfile, kEncodeSize,
                                              kIsHardwareEncoder, kSVCMode);
   base::RunLoop().RunUntilIdle();
-  EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(1u));
+  EXPECT_CALL(*mock_mojo_receiver(), SetEncodedFrameCount(kEncoderId, 1u));
   mojo_encoder_metrics_provider_->IncrementEncodedFrameCount();
   mojo_encoder_metrics_provider_->IncrementEncodedFrameCount();
   mojo_encoder_metrics_provider_->IncrementEncodedFrameCount();
@@ -145,7 +154,7 @@
   const media::EncoderStatus kErrorStatus(
       media::EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed");
   mojo_encoder_metrics_provider_->SetError(kErrorStatus);
-  EXPECT_CALL(*mock_mojo_receiver(), SetError(kErrorStatus));
+  EXPECT_CALL(*mock_mojo_receiver(), SetError(kEncoderId, kErrorStatus));
   base::RunLoop().RunUntilIdle();
 }
 
diff --git a/media/mojo/mojom/video_encoder_metrics_provider.mojom b/media/mojo/mojom/video_encoder_metrics_provider.mojom
index 403cd79c..8aa08f2 100644
--- a/media/mojo/mojom/video_encoder_metrics_provider.mojom
+++ b/media/mojo/mojom/video_encoder_metrics_provider.mojom
@@ -19,20 +19,28 @@
 
 // Provider interface to collect video encoder metrics.
 interface VideoEncoderMetricsProvider {
-  // Initialize() is called whenever the encoder configuration is changed.
+  // Initialize() is called whenever the encoder configuration is changed for
+  // the encoder whose id is |encoder_id|. This must be called for a new encoder
+  // before other calls. Otherwise, the other functions for the encoder is
+  // ignored.
   // The UKM about the encoding represented by the previous Initialize() is
   // reported if SetEncodedFrameCount() or SetError() is invoked. See
   // Media.VideoEncoderMetrics in ukm.xml for the detail about the recorded UKM.
-  Initialize(VideoEncoderUseCase encoder_use_case, VideoCodecProfile profile,
-             gfx.mojom.Size encode_size, bool is_hardware_encoder,
-             SVCScalabilityMode svc_mode);
+  Initialize(uint64 encoder_id, VideoEncoderUseCase encoder_use_case,
+             VideoCodecProfile profile, gfx.mojom.Size encode_size,
+             bool is_hardware_encoder, SVCScalabilityMode svc_mode);
 
   // SetEncodedFramesCount() updates the number of successfully encoded frames.
   // |num_encoded_frames| can be any value, but it is bucket by 100 when UKM
   // is recorded.
-  SetEncodedFrameCount(uint64 num_encoded_frames);
+  SetEncodedFrameCount(uint64 encoder_id, uint64 num_encoded_frames);
 
   // SetError() should be called when the encoder becomes in the error state. In
   // other words, |status| must not be kOk.
-  SetError(EncoderStatus status);
+  SetError(uint64 encoder_id, EncoderStatus status);
+
+  // Complete() is called when if the encoder whose id |encoder_id| is no longer
+  // used. This may not be called if the encoder is destroyed by destroying
+  // the renderer process (e.g. closing the tab).
+  Complete(uint64 encoder_id);
 };
diff --git a/media/mojo/services/mojo_video_encoder_metrics_provider_service.cc b/media/mojo/services/mojo_video_encoder_metrics_provider_service.cc
index ecaa779..62221b3e 100644
--- a/media/mojo/services/mojo_video_encoder_metrics_provider_service.cc
+++ b/media/mojo/services/mojo_video_encoder_metrics_provider_service.cc
@@ -7,12 +7,109 @@
 #include <algorithm>
 
 #include "base/memory/ptr_util.h"
+#include "base/strings/strcat.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 
 namespace media {
 
+class MojoVideoEncoderMetricsProviderService::EncoderMetricsHandler {
+ public:
+  EncoderMetricsHandler(const ukm::SourceId source_id,
+                        mojom::VideoEncoderUseCase encoder_use_case,
+                        VideoCodecProfile codec_profile,
+                        const gfx::Size& encode_size,
+                        bool is_hardware_encoder,
+                        SVCScalabilityMode svc_mode)
+      : source_id_(source_id),
+        encoder_use_case_(encoder_use_case),
+        codec_profile_(codec_profile),
+        encode_size_(encode_size),
+        is_hardware_encoder_(is_hardware_encoder),
+        svc_mode_(svc_mode) {}
+  ~EncoderMetricsHandler() { ReportUKM(); }
+
+  EncoderMetricsHandler(EncoderMetricsHandler&& handler)
+      : source_id_(handler.source_id_),
+        encoder_use_case_(handler.encoder_use_case_),
+        codec_profile_(handler.codec_profile_),
+        encode_size_(handler.encode_size_),
+        is_hardware_encoder_(handler.is_hardware_encoder_),
+        svc_mode_(handler.svc_mode_),
+        report_ukm_(true),
+        encoder_status_(handler.encoder_status_),
+        num_encoded_frames_(handler.num_encoded_frames_) {
+    // Set report ukm is false because the ukm should be reported in the created
+    // EncoderMetricsHandler.
+    handler.report_ukm_ = false;
+  }
+
+  EncoderMetricsHandler(const EncoderMetricsHandler&) = delete;
+  EncoderMetricsHandler& operator=(const EncoderMetricsHandler&) = delete;
+
+  void SetEncodedFrameCount(uint64_t num_encoded_frames) {
+    num_encoded_frames_ = num_encoded_frames;
+  }
+
+  void SetError(const media::EncoderStatus& status) {
+    CHECK(!status.is_ok());
+    if (encoder_status_.is_ok()) {
+      encoder_status_ = status;
+    }
+  }
+
+ private:
+  void ReportUKM() const {
+    if (!report_ukm_) {
+      return;
+    }
+
+    ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
+    if (!ukm_recorder) {
+      return;
+    }
+    ukm::builders::Media_VideoEncoderMetrics builder(source_id_);
+    builder.SetUseCase(static_cast<int>(encoder_use_case_));
+    builder.SetProfile(static_cast<int>(codec_profile_));
+    builder.SetSVCMode(static_cast<int>(svc_mode_));
+    builder.SetIsHardware(is_hardware_encoder_);
+    constexpr int kMaxResolutionBucket = 8200;
+    builder.SetWidth(
+        std::min(encode_size_.width() / 100 * 100, kMaxResolutionBucket));
+    builder.SetHeight(
+        std::min(encode_size_.height() / 100 * 100, kMaxResolutionBucket));
+    builder.SetStatus(static_cast<int>(encoder_status_.code()));
+
+    // We report UKM even if |num_encoded_frames_| is 0 so that we know how
+    // Initialize() is called. However, since the number of encoded frame is
+    // bucketed per 100, it disables to distinguish Initialize()-only case and
+    // the case of encoding a few frames. Therefore, we set the number of
+    // encoded frames to 1 if |num_encoded_frames_| is between 1 and 99.
+    if (num_encoded_frames_ == 0) {
+      builder.SetNumEncodedFrames(0);
+    } else {
+      builder.SetNumEncodedFrames(
+          std::max<uint64_t>(1, num_encoded_frames_ / 100 * 100));
+    }
+    builder.Record(ukm_recorder);
+
+    // TODO(b/275663480): Report UMAs.
+  }
+
+  const ukm::SourceId source_id_;
+  const mojom::VideoEncoderUseCase encoder_use_case_;
+  const VideoCodecProfile codec_profile_;
+  const gfx::Size encode_size_;
+  const bool is_hardware_encoder_;
+  const SVCScalabilityMode svc_mode_;
+
+  bool report_ukm_ = true;
+
+  EncoderStatus encoder_status_ = EncoderStatus::Codes::kOk;
+  uint64_t num_encoded_frames_ = 0;
+};
+
 // static
 void MojoVideoEncoderMetricsProviderService::Create(
     ukm::SourceId source_id,
@@ -27,75 +124,50 @@
     : source_id_(source_id) {}
 
 MojoVideoEncoderMetricsProviderService::
-    ~MojoVideoEncoderMetricsProviderService() {
-  ReportUKMIfNeeded();
-}
-
-void MojoVideoEncoderMetricsProviderService::ReportUKMIfNeeded() const {
-  // If Initialize() is not called, no UKM is reported.
-  if (!initialized_) {
-    return;
-  }
-  ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
-  if (!ukm_recorder) {
-    return;
-  }
-  ukm::builders::Media_VideoEncoderMetrics builder(source_id_);
-  builder.SetUseCase(static_cast<int>(encoder_use_case_));
-  builder.SetProfile(static_cast<int>(codec_profile_));
-  builder.SetSVCMode(static_cast<int>(svc_mode_));
-  builder.SetIsHardware(is_hardware_encoder_);
-  constexpr int kMaxResolutionBucket = 8200;
-  builder.SetWidth(
-      std::min(encode_size_.width() / 100 * 100, kMaxResolutionBucket));
-  builder.SetHeight(
-      std::min(encode_size_.height() / 100 * 100, kMaxResolutionBucket));
-  builder.SetStatus(static_cast<int>(encoder_status_.code()));
-
-  // We report UKM even if |num_encoded_frames_| is 0 so that we know how
-  // Initialize() is called. However, since the number of encoded frame is
-  // bucketed per 100, it disables to distinguish Initialize()-only case and
-  // the case of encoding a few frames. Therefore, we set the number of encoded
-  // frames to 1 if |num_encoded_frames_| is between 1 and 99.
-  if (num_encoded_frames_ == 0) {
-    builder.SetNumEncodedFrames(0);
-  } else {
-    builder.SetNumEncodedFrames(
-        std::max<uint64_t>(1, num_encoded_frames_ / 100 * 100));
-  }
-  builder.Record(ukm_recorder);
-
-  // TODO(b/275663480): Report UMAs.
-}
+    ~MojoVideoEncoderMetricsProviderService() = default;
 
 void MojoVideoEncoderMetricsProviderService::Initialize(
+    uint64_t encoder_id,
     mojom::VideoEncoderUseCase encoder_use_case,
     VideoCodecProfile codec_profile,
     const gfx::Size& encode_size,
     bool is_hardware_encoder,
     SVCScalabilityMode svc_mode) {
-  ReportUKMIfNeeded();
-  initialized_ = true;
-  num_encoded_frames_ = 0;
-  encoder_use_case_ = encoder_use_case;
-  codec_profile_ = codec_profile;
-  encode_size_ = encode_size;
-  is_hardware_encoder_ = is_hardware_encoder;
-  encoder_status_ = EncoderStatus::Codes::kOk;
-  svc_mode_ = svc_mode;
+  encoders_.erase(encoder_id);
+  encoders_.emplace(
+      encoder_id,
+      EncoderMetricsHandler(source_id_, encoder_use_case, codec_profile,
+                            encode_size, is_hardware_encoder, svc_mode));
 }
 
 void MojoVideoEncoderMetricsProviderService::SetEncodedFrameCount(
+    uint64_t encoder_id,
     uint64_t num_encoded_frames) {
-  num_encoded_frames_ = num_encoded_frames;
+  auto it = encoders_.find(encoder_id);
+  if (it == encoders_.end()) {
+    mojo::ReportBadMessage(base::StrCat(
+        {"Unknown encoder id: ", base::NumberToString(encoder_id)}));
+    return;
+  }
+  it->second.SetEncodedFrameCount(num_encoded_frames);
 }
 
 void MojoVideoEncoderMetricsProviderService::SetError(
+    uint64_t encoder_id,
     const EncoderStatus& status) {
-  CHECK(!status.is_ok());
-  if (encoder_status_.is_ok()) {
-    encoder_status_ = status;
+  auto it = encoders_.find(encoder_id);
+  if (it == encoders_.end()) {
+    mojo::ReportBadMessage(base::StrCat(
+        {"Unknown encoder id: ", base::NumberToString(encoder_id)}));
+    return;
   }
+  it->second.SetError(status);
 }
 
+void MojoVideoEncoderMetricsProviderService::Complete(uint64_t encoder_id) {
+  if (encoders_.erase(encoder_id) == 0u) {
+    mojo::ReportBadMessage(base::StrCat(
+        {"Unknown encoder id: ", base::NumberToString(encoder_id)}));
+  }
+}
 }  // namespace media
diff --git a/media/mojo/services/mojo_video_encoder_metrics_provider_service.h b/media/mojo/services/mojo_video_encoder_metrics_provider_service.h
index ce3ce9c6..706f1f8 100644
--- a/media/mojo/services/mojo_video_encoder_metrics_provider_service.h
+++ b/media/mojo/services/mojo_video_encoder_metrics_provider_service.h
@@ -5,13 +5,9 @@
 #ifndef MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODER_METRICS_PROVIDER_SERVICE_H_
 #define MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODER_METRICS_PROVIDER_SERVICE_H_
 
-#include "media/base/encoder_status.h"
-#include "media/base/svc_scalability_mode.h"
-#include "media/base/video_codecs.h"
 #include "media/mojo/mojom/video_encoder_metrics_provider.mojom.h"
 #include "media/mojo/services/media_mojo_export.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
-#include "ui/gfx/geometry/size.h"
 
 namespace media {
 
@@ -26,29 +22,25 @@
   ~MojoVideoEncoderMetricsProviderService() override;
 
   // mojom::VideoEncoderMetricsProvider implementation.
-  void Initialize(mojom::VideoEncoderUseCase encoder_use_case,
+  void Initialize(uint64_t encoder_id,
+                  mojom::VideoEncoderUseCase encoder_use_case,
                   VideoCodecProfile codec_profile,
                   const gfx::Size& encode_size,
                   bool is_hardware_encoder,
                   SVCScalabilityMode svc_mode) override;
-  void SetEncodedFrameCount(uint64_t num_encoded_frames) override;
-  void SetError(const EncoderStatus& status) override;
+  void SetEncodedFrameCount(uint64_t encoder_id,
+                            uint64_t num_encoded_frames) override;
+  void SetError(uint64_t encoder_id, const EncoderStatus& status) override;
+  void Complete(uint64_t encoder_id) override;
 
  private:
+  class EncoderMetricsHandler;
+
   explicit MojoVideoEncoderMetricsProviderService(ukm::SourceId source_id);
 
-  void ReportUKMIfNeeded() const;
-
   const ukm::SourceId source_id_;
-  bool initialized_ = false;
-  uint64_t num_encoded_frames_ = 0;
 
-  mojom::VideoEncoderUseCase encoder_use_case_;
-  VideoCodecProfile codec_profile_;
-  gfx::Size encode_size_;
-  bool is_hardware_encoder_;
-  SVCScalabilityMode svc_mode_;
-  EncoderStatus encoder_status_;
+  std::map<uint64_t, EncoderMetricsHandler> encoders_;
 };
 }  // namespace media
-#endif  // MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODER_METRICS_PROVIDER_SERVICE_H_
+#endif  // MEDIA_MOJO_SERVICES_VIDEO_ENCODER_METRICS_PROVIDER_H_
diff --git a/media/mojo/services/mojo_video_encoder_metrics_provider_service_unittest.cc b/media/mojo/services/mojo_video_encoder_metrics_provider_service_unittest.cc
index 7dd4e2a1..64ce0629 100644
--- a/media/mojo/services/mojo_video_encoder_metrics_provider_service_unittest.cc
+++ b/media/mojo/services/mojo_video_encoder_metrics_provider_service_unittest.cc
@@ -39,7 +39,8 @@
 }  // namespace
 
 class MojoVideoEncoderMetricsProviderServiceTest
-    : public TestWithParam<testing::tuple<mojom::VideoEncoderUseCase,
+    : public TestWithParam<testing::tuple<uint64_t,
+                                          mojom::VideoEncoderUseCase,
                                           VideoCodecProfile,
                                           gfx::Size,
                                           bool,
@@ -66,12 +67,13 @@
 TEST_F(MojoVideoEncoderMetricsProviderServiceTest,
        CreateAndInitialize_ReportUKM) {
   auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kEncoderId = 0;
   constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
   constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
   constexpr gfx::Size kEncodeSize(1200, 700);
   constexpr bool kIsHardwareEncoder = true;
   constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
-  provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize,
+  provider->Initialize(kEncoderId, kEncoderUseCase, kCodecProfile, kEncodeSize,
                        kIsHardwareEncoder, kSVCMode);
   provider.reset();
   base::RunLoop().RunUntilIdle();
@@ -90,18 +92,48 @@
   EXPECT_UKM(UkmEntry::kWidthName, kEncodeSize.width());
 }
 
-TEST_F(
-    MojoVideoEncoderMetricsProviderServiceTest,
-    CreateAndInitializeAndSetSmallNumberEncodedFrameCount_ReportUKMWithOneBucket) {
+TEST_F(MojoVideoEncoderMetricsProviderServiceTest,
+       CreateAndInitializeAndComplete_ReportUKM) {
   auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kEncoderId = 0;
   constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
   constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
   constexpr gfx::Size kEncodeSize(1200, 700);
   constexpr bool kIsHardwareEncoder = true;
   constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
-  provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize,
+  provider->Initialize(kEncoderId, kEncoderUseCase, kCodecProfile, kEncodeSize,
                        kIsHardwareEncoder, kSVCMode);
-  provider->SetEncodedFrameCount(10);
+  provider->Complete(kEncoderId);
+  base::RunLoop().RunUntilIdle();
+
+  const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName);
+  ASSERT_EQ(1u, entries.size());
+  const auto* entry = entries[0];
+  EXPECT_UKM(UkmEntry::kHeightName, kEncodeSize.height());
+  EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder);
+  EXPECT_UKM(UkmEntry::kNumEncodedFramesName, 0);
+  EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile);
+  EXPECT_UKM(UkmEntry::kStatusName,
+             static_cast<int64_t>(EncoderStatus::Codes::kOk));
+  EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode));
+  EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase));
+  EXPECT_UKM(UkmEntry::kWidthName, kEncodeSize.width());
+  provider.reset();
+}
+
+TEST_F(
+    MojoVideoEncoderMetricsProviderServiceTest,
+    CreateAndInitializeAndSetSmallNumberEncodedFrameCount_ReportUKMWithOneBucket) {
+  auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kEncoderId = 0;
+  constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
+  constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
+  constexpr gfx::Size kEncodeSize(1200, 700);
+  constexpr bool kIsHardwareEncoder = true;
+  constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
+  provider->Initialize(kEncoderId, kEncoderUseCase, kCodecProfile, kEncodeSize,
+                       kIsHardwareEncoder, kSVCMode);
+  provider->SetEncodedFrameCount(kEncoderId, 10);
   provider.reset();
   base::RunLoop().RunUntilIdle();
 
@@ -122,15 +154,16 @@
 TEST_P(MojoVideoEncoderMetricsProviderServiceTest,
        CreateAndInitializeAndSetEncodedFrameCount_ReportUKM) {
   auto [test_recorder, provider] = Create(kTestURL);
-  auto encoder_use_case = std::get<0>(GetParam());
-  auto codec_profile = std::get<1>(GetParam());
-  auto encode_size = std::get<2>(GetParam());
-  auto is_hardware_encoder = std::get<3>(GetParam());
-  auto svc_mode = std::get<4>(GetParam());
+  auto encoder_id = std::get<0>(GetParam());
+  auto encoder_use_case = std::get<1>(GetParam());
+  auto codec_profile = std::get<2>(GetParam());
+  auto encode_size = std::get<3>(GetParam());
+  auto is_hardware_encoder = std::get<4>(GetParam());
+  auto svc_mode = std::get<5>(GetParam());
   constexpr uint64_t kNumEncodedFrames = 100;
-  provider->Initialize(encoder_use_case, codec_profile, encode_size,
+  provider->Initialize(encoder_id, encoder_use_case, codec_profile, encode_size,
                        is_hardware_encoder, svc_mode);
-  provider->SetEncodedFrameCount(kNumEncodedFrames);
+  provider->SetEncodedFrameCount(encoder_id, kNumEncodedFrames);
   provider.reset();
   base::RunLoop().RunUntilIdle();
 
@@ -153,7 +186,8 @@
 INSTANTIATE_TEST_SUITE_P(
     All,
     MojoVideoEncoderMetricsProviderServiceTest,
-    ::testing::Combine(ValuesIn({
+    ::testing::Combine(ValuesIn(std::vector<uint64_t>{12ul, 100ul}),
+                       ValuesIn({
                            mojom::VideoEncoderUseCase::kCastMirroring,
                            mojom::VideoEncoderUseCase::kMediaRecorder,
                            mojom::VideoEncoderUseCase::kWebCodecs,
@@ -178,15 +212,16 @@
 TEST_F(MojoVideoEncoderMetricsProviderServiceTest,
        InitializeWithVerfiyLargeResoloution_ReportCappedResolutionUKM) {
   auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kEncoderId = 0;
   constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
   constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
   constexpr gfx::Size k16kEncodeSize(15360, 8640);
   constexpr bool kIsHardwareEncoder = true;
   constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
   constexpr uint64_t kNumEncodedFrames = 100;
-  provider->Initialize(kEncoderUseCase, kCodecProfile, k16kEncodeSize,
-                       kIsHardwareEncoder, kSVCMode);
-  provider->SetEncodedFrameCount(kNumEncodedFrames);
+  provider->Initialize(kEncoderId, kEncoderUseCase, kCodecProfile,
+                       k16kEncodeSize, kIsHardwareEncoder, kSVCMode);
+  provider->SetEncodedFrameCount(kEncoderId, kNumEncodedFrames);
   provider.reset();
   base::RunLoop().RunUntilIdle();
 
@@ -209,16 +244,17 @@
 TEST_F(MojoVideoEncoderMetricsProviderServiceTest,
        CallSetEncodedFrameCounts_ReportUKMWithTheLastEncodedFrameCount) {
   auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kEncoderId = 0;
   constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
   constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
   constexpr gfx::Size kEncodeSize(1920, 1080);
   constexpr bool kIsHardwareEncoder = true;
   constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
-  provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize,
+  provider->Initialize(kEncoderId, kEncoderUseCase, kCodecProfile, kEncodeSize,
                        kIsHardwareEncoder, kSVCMode);
-  provider->SetEncodedFrameCount(100);
-  provider->SetEncodedFrameCount(200);
-  provider->SetEncodedFrameCount(300);
+  provider->SetEncodedFrameCount(kEncoderId, 100);
+  provider->SetEncodedFrameCount(kEncoderId, 200);
+  provider->SetEncodedFrameCount(kEncoderId, 300);
   provider.reset();
   base::RunLoop().RunUntilIdle();
 
@@ -241,17 +277,19 @@
 TEST_F(MojoVideoEncoderMetricsProviderServiceTest,
        CreateAndInitializeAndCallSetErrors_ReportUKMWithTheFirstError) {
   auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kEncoderId = 0;
   constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
   constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
   constexpr gfx::Size kEncodeSize(1920, 1080);
   constexpr bool kIsHardwareEncoder = true;
   constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
-  provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize,
+  provider->Initialize(kEncoderId, kEncoderUseCase, kCodecProfile, kEncodeSize,
                        kIsHardwareEncoder, kSVCMode);
-  provider->SetError({EncoderStatus::Codes::kEncoderMojoConnectionError,
+  provider->SetError(kEncoderId,
+                     {EncoderStatus::Codes::kEncoderMojoConnectionError,
                       "mojo connection is disclosed"});
-  provider->SetError(
-      {EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed"});
+  provider->SetError(kEncoderId, {EncoderStatus::Codes::kEncoderFailedEncode,
+                                  "Encoder failed"});
   provider.reset();
   base::RunLoop().RunUntilIdle();
 
@@ -275,17 +313,19 @@
 TEST_F(MojoVideoEncoderMetricsProviderServiceTest,
        CallErrorAndNoCallSetEncodedFramesCount_ReportUKMWithTheFirstError) {
   auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kEncoderId = 0;
   constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
   constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
   constexpr gfx::Size kEncodeSize(1920, 1080);
   constexpr bool kIsHardwareEncoder = true;
   constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
-  provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize,
+  provider->Initialize(kEncoderId, kEncoderUseCase, kCodecProfile, kEncodeSize,
                        kIsHardwareEncoder, kSVCMode);
-  provider->SetError({EncoderStatus::Codes::kEncoderMojoConnectionError,
+  provider->SetError(kEncoderId,
+                     {EncoderStatus::Codes::kEncoderMojoConnectionError,
                       "mojo connection is disclosed"});
-  provider->SetError(
-      {EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed"});
+  provider->SetError(kEncoderId, {EncoderStatus::Codes::kEncoderFailedEncode,
+                                  "Encoder failed"});
   provider.reset();
   base::RunLoop().RunUntilIdle();
 
@@ -310,21 +350,22 @@
     MojoVideoEncoderMetricsProviderServiceTest,
     CallSetEncodedFrameCountsAndSetError_ReportUKMWithTheFirstErrorAndTheLastEncodedFrameCount) {
   auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kEncoderId = 0;
   constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
   constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
   constexpr gfx::Size kEncodeSize(1920, 1080);
   constexpr bool kIsHardwareEncoder = true;
   constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
-  provider->Initialize(kEncoderUseCase, kCodecProfile, kEncodeSize,
+  provider->Initialize(kEncoderId, kEncoderUseCase, kCodecProfile, kEncodeSize,
                        kIsHardwareEncoder, kSVCMode);
-  provider->SetEncodedFrameCount(100);
-  provider->SetEncodedFrameCount(200);
-  provider->SetEncodedFrameCount(300);
-  provider->SetError(
-      {EncoderStatus::Codes::kEncoderFailedEncode, "Encoder failed"});
-  provider->SetError(
-      {EncoderStatus::Codes::kEncoderIllegalState, "Encoder illegal state"});
-  provider->SetEncodedFrameCount(400);
+  provider->SetEncodedFrameCount(kEncoderId, 100);
+  provider->SetEncodedFrameCount(kEncoderId, 200);
+  provider->SetEncodedFrameCount(kEncoderId, 300);
+  provider->SetError(kEncoderId, {EncoderStatus::Codes::kEncoderFailedEncode,
+                                  "Encoder failed"});
+  provider->SetError(kEncoderId, {EncoderStatus::Codes::kEncoderIllegalState,
+                                  "Encoder illegal state"});
+  provider->SetEncodedFrameCount(kEncoderId, 400);
   provider.reset();
   base::RunLoop().RunUntilIdle();
 
@@ -374,13 +415,14 @@
           300,
       },
   };
+  constexpr uint64_t kEncoderId = 0;
   auto [test_recorder, provider] = Create(kTestURL);
   for (const auto& metrics : kMetricsCases) {
-    provider->Initialize(metrics.use_case, metrics.profile, metrics.size,
-                         metrics.is_hardware, metrics.svc_mode);
-    provider->SetEncodedFrameCount(metrics.num_encoded_frames);
+    provider->Initialize(kEncoderId, metrics.use_case, metrics.profile,
+                         metrics.size, metrics.is_hardware, metrics.svc_mode);
+    provider->SetEncodedFrameCount(kEncoderId, metrics.num_encoded_frames);
     if (metrics.status != EncoderStatus::Codes::kOk) {
-      provider->SetError(metrics.status);
+      provider->SetError(kEncoderId, metrics.status);
     }
   }
   provider.reset();
@@ -402,5 +444,110 @@
   }
 }
 
+TEST_F(MojoVideoEncoderMetricsProviderServiceTest, HandleTwoEncoders) {
+  const struct {
+    uint64_t encoder_id;
+    mojom::VideoEncoderUseCase use_case;
+    VideoCodecProfile profile;
+    gfx::Size size;
+    bool is_hardware;
+    SVCScalabilityMode svc_mode;
+    EncoderStatus::Codes status;
+    uint64_t num_encoded_frames;
+  } kMetricsCases[] = {
+      {
+          0,
+          mojom::VideoEncoderUseCase::kWebRTC,
+          VP9PROFILE_PROFILE0,
+          gfx::Size(600, 300),
+          true,
+          SVCScalabilityMode::kL2T3Key,
+          EncoderStatus::Codes::kEncoderIllegalState,
+          100,
+      },
+      {
+          1,
+          mojom::VideoEncoderUseCase::kMediaRecorder,
+          H264PROFILE_HIGH,
+          gfx::Size(1200, 700),
+          /*is_hardware=*/true,
+          SVCScalabilityMode::kL2T3Key,
+          EncoderStatus::Codes::kOk,
+          300,
+      },
+  };
+  auto [test_recorder, provider] = Create(kTestURL);
+  for (const auto& metrics : kMetricsCases) {
+    provider->Initialize(metrics.encoder_id, metrics.use_case, metrics.profile,
+                         metrics.size, metrics.is_hardware, metrics.svc_mode);
+  }
+  for (const auto& metrics : kMetricsCases) {
+    provider->SetEncodedFrameCount(metrics.encoder_id,
+                                   metrics.num_encoded_frames);
+  }
+  for (const auto& metrics : kMetricsCases) {
+    if (metrics.status != EncoderStatus::Codes::kOk) {
+      provider->SetError(metrics.encoder_id, metrics.status);
+    }
+  }
+  for (const auto& metrics : kMetricsCases) {
+    provider->Complete(metrics.encoder_id);
+  }
+  provider.reset();
+  base::RunLoop().RunUntilIdle();
+
+  const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName);
+  ASSERT_EQ(std::size(kMetricsCases), entries.size());
+  for (size_t i = 0; i < entries.size(); ++i) {
+    const auto* entry = entries[i];
+    const auto& metrics = kMetricsCases[i];
+    EXPECT_UKM(UkmEntry::kHeightName, metrics.size.height());
+    EXPECT_UKM(UkmEntry::kIsHardwareName, metrics.is_hardware);
+    EXPECT_UKM(UkmEntry::kNumEncodedFramesName, metrics.num_encoded_frames);
+    EXPECT_UKM(UkmEntry::kProfileName, metrics.profile);
+    EXPECT_UKM(UkmEntry::kStatusName, static_cast<int64_t>(metrics.status));
+    EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(metrics.svc_mode));
+    EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(metrics.use_case));
+    EXPECT_UKM(UkmEntry::kWidthName, metrics.size.width());
+  }
+}
+
+TEST_F(MojoVideoEncoderMetricsProviderServiceTest, IgnoreUnknownEncoderIds) {
+  auto [test_recorder, provider] = Create(kTestURL);
+  constexpr uint64_t kKnownEncoderId = 123;
+  constexpr uint64_t kUnknownEncoderId = 321;
+  constexpr auto kEncoderUseCase = mojom::VideoEncoderUseCase::kWebRTC;
+  constexpr auto kCodecProfile = VP9PROFILE_PROFILE0;
+  constexpr gfx::Size kEncodeSize(1200, 700);
+  constexpr bool kIsHardwareEncoder = true;
+  constexpr auto kSVCMode = SVCScalabilityMode::kL1T3;
+  provider->Initialize(kKnownEncoderId, kEncoderUseCase, kCodecProfile,
+                       kEncodeSize, kIsHardwareEncoder, kSVCMode);
+  provider->SetEncodedFrameCount(kUnknownEncoderId, 100);
+  provider->SetError(kUnknownEncoderId,
+                     EncoderStatus::Codes::kEncoderFailedEncode);
+  provider->Complete(kUnknownEncoderId);
+
+  provider->Complete(kKnownEncoderId);
+  // This should be ignored as Complete() is already called.
+  provider->SetError(kKnownEncoderId,
+                     EncoderStatus::Codes::kEncoderFailedEncode);
+
+  provider.reset();
+  base::RunLoop().RunUntilIdle();
+
+  const auto entries = test_recorder->GetEntriesByName(UkmEntry::kEntryName);
+  ASSERT_EQ(1u, entries.size());
+  const auto* entry = entries[0];
+  EXPECT_UKM(UkmEntry::kHeightName, kEncodeSize.height());
+  EXPECT_UKM(UkmEntry::kIsHardwareName, kIsHardwareEncoder);
+  EXPECT_UKM(UkmEntry::kNumEncodedFramesName, 0);
+  EXPECT_UKM(UkmEntry::kProfileName, kCodecProfile);
+  EXPECT_UKM(UkmEntry::kStatusName,
+             static_cast<int64_t>(EncoderStatus::Codes::kOk));
+  EXPECT_UKM(UkmEntry::kSVCModeName, static_cast<int64_t>(kSVCMode));
+  EXPECT_UKM(UkmEntry::kUseCaseName, static_cast<int64_t>(kEncoderUseCase));
+  EXPECT_UKM(UkmEntry::kWidthName, kEncodeSize.width());
+}
 #undef EXPECT_UKM
 }  // namespace media
diff --git a/net/base/features.cc b/net/base/features.cc
index 5569670..f51f094b 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -365,10 +365,6 @@
     &kEnableIpProtectionProxy, /*name=*/"IpPrivacyProxyServer",
     /*default_value=*/""};
 
-const base::FeatureParam<std::string> kIpPrivacyProxyAllowlist{
-    &kEnableIpProtectionProxy, /*name=*/"IpPrivacyProxyAllowlist",
-    /*default_value=*/""};
-
 const base::FeatureParam<std::string> kIpPrivacyTokenServer{
     &kEnableIpProtectionProxy, /*name=*/"IpPrivacyTokenServer",
     /*default_value=*/"https://autopush-phosphor-pa.sandbox.googleapis.com"};
diff --git a/net/base/features.h b/net/base/features.h
index c22eb086..333e7cc 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -381,10 +381,6 @@
 // Sets the name of the IP protection proxy.
 NET_EXPORT extern const base::FeatureParam<std::string> kIpPrivacyProxyServer;
 
-// Sets the allow list for the IP protection proxy.
-NET_EXPORT extern const base::FeatureParam<std::string>
-    kIpPrivacyProxyAllowlist;
-
 // Sets the name of the IP protection auth token server.
 NET_EXPORT extern const base::FeatureParam<std::string> kIpPrivacyTokenServer;
 
diff --git a/services/network/network_service_proxy_allow_list.cc b/services/network/network_service_proxy_allow_list.cc
index c6860b9..327b2e3 100644
--- a/services/network/network_service_proxy_allow_list.cc
+++ b/services/network/network_service_proxy_allow_list.cc
@@ -4,13 +4,12 @@
 //
 #include "services/network/network_service_proxy_allow_list.h"
 
-#include "base/command_line.h"
 #include "base/strings/strcat.h"
 #include "components/privacy_sandbox/masked_domain_list/masked_domain_list.pb.h"
+#include "net/base/features.h"
 #include "net/base/schemeful_site.h"
 #include "net/proxy_resolution/proxy_bypass_rules.h"
 #include "services/network/public/cpp/features.h"
-#include "services/network/public/cpp/network_switches.h"
 
 namespace network {
 namespace {
@@ -41,17 +40,8 @@
 NetworkServiceProxyAllowList::NetworkServiceProxyAllowList() {
   custom_proxy_config_ = network::mojom::CustomProxyConfig::New();
 
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-
-  std::string ip_protection_proxy_server =
-      command_line.HasSwitch(network::switches::kIPAnonymizationProxyServer)
-          ? command_line.GetSwitchValueASCII(
-                network::switches::kIPAnonymizationProxyServer)
-          : net::features::kIpPrivacyProxyServer.Get();
-
   std::string proxy_spec =
-      base::StrCat({ip_protection_proxy_server, ",direct://"});
+      base::StrCat({net::features::kIpPrivacyProxyServer.Get(), ",direct://"});
   custom_proxy_config_->rules.ParseFromString(proxy_spec);
 
   custom_proxy_config_->rules.restrict_to_network_service_proxy_allow_list =
diff --git a/services/network/public/cpp/network_switches.cc b/services/network/public/cpp/network_switches.cc
index 72fe2fb..d011c40 100644
--- a/services/network/public/cpp/network_switches.cc
+++ b/services/network/public/cpp/network_switches.cc
@@ -35,23 +35,6 @@
 const char kIgnoreCertificateErrorsSPKIList[] =
     "ignore-certificate-errors-spki-list";
 
-// Specifies a proxy server for origins specified in
-// kIPAnonymizationProxyAllowList. This proxy will be used on a best-effort
-// basis when normal proxy resolution would result in trying direct connections
-// (possibly after trying some other proxy server).
-const char kIPAnonymizationProxyServer[] = "ip-anonymization-proxy-server";
-
-// Specifies a list of origins on which to use the server specified by
-// `kIPAnonymizationProxyServer`. if `kIPAnonymizationProxyServer` is empty this
-// list will be ignored. This is intended as a reverse bypass rules list.
-const char kIPAnonymizationProxyAllowList[] =
-    "ip-anonymization-proxy-allow-list";
-
-// Specifies a value for the "password" header to be passed to the proxy
-// specified by `kIPAnonymizationProxyServer`. if `kIPAnonymizationProxyServer`
-// is empty this list will be ignored.
-const char kIPAnonymizationProxyPassword[] = "ip-anonymization-proxy-password";
-
 // Enables saving net log events to a file. If a value is given, it used as the
 // path the the file, otherwise the file is named netlog.json and placed in the
 // user data directory.
diff --git a/services/network/public/cpp/network_switches.h b/services/network/public/cpp/network_switches.h
index 30d296f..7020e49c 100644
--- a/services/network/public/cpp/network_switches.h
+++ b/services/network/public/cpp/network_switches.h
@@ -17,10 +17,6 @@
 COMPONENT_EXPORT(NETWORK_CPP)
 extern const char kIgnoreCertificateErrorsSPKIList[];
 COMPONENT_EXPORT(NETWORK_CPP) extern const char kIgnoreUrlFetcherCertRequests[];
-COMPONENT_EXPORT(NETWORK_CPP) extern const char kIPAnonymizationProxyServer[];
-COMPONENT_EXPORT(NETWORK_CPP)
-extern const char kIPAnonymizationProxyAllowList[];
-COMPONENT_EXPORT(NETWORK_CPP) extern const char kIPAnonymizationProxyPassword[];
 COMPONENT_EXPORT(NETWORK_CPP) extern const char kLogNetLog[];
 COMPONENT_EXPORT(NETWORK_CPP) extern const char kNetLogCaptureMode[];
 COMPONENT_EXPORT(NETWORK_CPP) extern const char kNetLogMaxSizeMb[];
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index 63cb1ce7d..b9018dc 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -1321,7 +1321,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R118-15574.0.0",
+        "cros_img": "octopus-release/R118-15585.0.0",
         "name": "chrome_all_tast_tests OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 10,
         "tast_expr": "(\"group:mainline\" && \"dep:chrome\" && !\"dep:no_chrome_dcheck\" && !\"dep:lacros\" && !informational)",
@@ -1450,7 +1450,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "dedede",
-        "cros_img": "dedede-release/R118-15574.0.0",
+        "cros_img": "dedede-release/R118-15585.0.0",
         "name": "lacros_all_tast_tests DEDEDE_RELEASE_LKGM",
         "resultdb": {
           "enable": true,
@@ -1515,7 +1515,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "eve",
-        "cros_img": "eve-release/R118-15574.0.0",
+        "cros_img": "eve-release/R118-15585.0.0",
         "name": "lacros_all_tast_tests EVE_RELEASE_LKGM",
         "resultdb": {
           "enable": true,
@@ -1612,7 +1612,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R117-15564.0.0",
+        "cros_img": "jacuzzi-release/R118-15585.0.0",
         "name": "lacros_all_tast_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
           "enable": true,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index b1d8b9a..8afff13 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -1415,7 +1415,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "volteer",
-        "cros_img": "volteer-public/R118-15574.0.0",
+        "cros_img": "volteer-public/R118-15585.0.0",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests VOLTEER_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
@@ -1507,7 +1507,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R117-15564.0.0",
+        "cros_img": "jacuzzi-public/R118-15585.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -1536,7 +1536,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "kevin",
-        "cros_img": "kevin64-public/R118-15574.0.0",
+        "cros_img": "kevin64-public/R118-15585.0.0",
         "name": "lacros_all_tast_tests KEVIN64_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -4886,9 +4886,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -4898,8 +4898,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -5033,9 +5033,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5045,8 +5045,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -5165,9 +5165,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5177,8 +5177,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 01700f3..6dfc587 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -25056,9 +25056,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25068,8 +25068,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -25203,9 +25203,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25215,8 +25215,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -25335,9 +25335,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25347,8 +25347,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index d1c2abd..dc710509 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -40346,7 +40346,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "octopus",
-        "cros_img": "octopus-public/R118-15574.0.0",
+        "cros_img": "octopus-public/R118-15585.0.0",
         "name": "lacros_all_tast_tests OCTOPUS_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -40363,7 +40363,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "eve",
-        "cros_img": "eve-public/R118-15574.0.0",
+        "cros_img": "eve-public/R118-15585.0.0",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests EVE_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
@@ -40390,7 +40390,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R117-15564.0.0",
+        "cros_img": "jacuzzi-public/R118-15585.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -40407,7 +40407,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "kevin",
-        "cros_img": "kevin64-public/R118-15574.0.0",
+        "cros_img": "kevin64-public/R118-15585.0.0",
         "name": "lacros_all_tast_tests KEVIN64_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -40431,7 +40431,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R117-15564.0.0",
+        "cros_img": "jacuzzi-public/R118-15585.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -40448,7 +40448,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R117-15564.0.0",
+        "cros_img": "jacuzzi-public/R118-15585.0.0",
         "name": "lacros_all_tast_tests JACUZZI_CQ_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
         "public_builder_bucket": "testplatform-public",
@@ -40467,7 +40467,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "kevin",
-        "cros_img": "kevin64-public/R118-15574.0.0",
+        "cros_img": "kevin64-public/R118-15585.0.0",
         "name": "lacros_all_tast_tests KEVIN64_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -42686,9 +42686,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -42697,8 +42697,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -42833,9 +42833,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -42844,8 +42844,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -42965,9 +42965,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -42976,8 +42976,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -44211,9 +44211,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44222,8 +44222,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -44358,9 +44358,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44369,8 +44369,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -44490,9 +44490,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44501,8 +44501,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -45133,9 +45133,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -45144,8 +45144,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 69a2379..45cc330 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -16123,12 +16123,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16138,8 +16138,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -16290,12 +16290,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16305,8 +16305,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
@@ -16437,12 +16437,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 118.0.5964.0",
+        "description": "Run with ash-chrome version 118.0.5965.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16452,8 +16452,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v118.0.5964.0",
-              "revision": "version:118.0.5964.0"
+              "location": "lacros_version_skew_tests_v118.0.5965.0",
+              "revision": "version:118.0.5965.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/filters/cr23.linux.cr23_interactive_ui_tests.filter b/testing/buildbot/filters/cr23.linux.cr23_interactive_ui_tests.filter
index df2f3d9..1b76a99b 100644
--- a/testing/buildbot/filters/cr23.linux.cr23_interactive_ui_tests.filter
+++ b/testing/buildbot/filters/cr23.linux.cr23_interactive_ui_tests.filter
@@ -11,6 +11,4 @@
 -PriceTrackingIconViewErrorHandelingTest.IconRevertedOnFailure
 -PriceTrackingIconViewInteractiveTest.EnablePriceTrackOnPress
 -PriceTrackingIconViewInteractiveTest.TrackedProductIsDifferentBookmark
--TabDragging/DetachToBrowserTabDragControllerTest.DragMultipleTabsRightIntoGroup/0
--TabDragging/DetachToBrowserTabDragControllerTest.DragMultipleTabsRightIntoGroup/1
 -TabHoverCardInteractiveUiTest.HoverCardHidesOnMouseExit
diff --git a/testing/buildbot/filters/cr23.mac.cr23_interactive_ui_tests.filter b/testing/buildbot/filters/cr23.mac.cr23_interactive_ui_tests.filter
index 40c6389..6183368f 100644
--- a/testing/buildbot/filters/cr23.mac.cr23_interactive_ui_tests.filter
+++ b/testing/buildbot/filters/cr23.mac.cr23_interactive_ui_tests.filter
@@ -1,8 +1,6 @@
 # cr23_interactive_ui_tests that are expected to fail on mac bots:
 -All/ExtensionsMenuModelPresenceTest.MenuPresence/0
 -AppMenuFullscreenInteractiveTest.ClosingTab
--TabDragging/DetachToBrowserTabDragControllerTest.DragMultipleTabsRightIntoGroup/0
--TabDragging/DetachToBrowserTabDragControllerTest.DragMultipleTabsRightIntoGroup/1
 -PermissionIndicatorsInteractiveUITest.CameraAccessAndStopTest
 -PermissionIndicatorsInteractiveUITest.CameraAndMicAccessAndStopTest
 -PermissionsFlowInteractiveUITest.CameraActivityIndicatorTest
diff --git a/testing/buildbot/filters/linux-lacros.browser_tests.filter b/testing/buildbot/filters/linux-lacros.browser_tests.filter
index 1b458db..2bb1116d 100644
--- a/testing/buildbot/filters/linux-lacros.browser_tests.filter
+++ b/testing/buildbot/filters/linux-lacros.browser_tests.filter
@@ -3,3 +3,7 @@
 -All/HostedOrWebAppTest.CtrlClickLink/HostedApp
 -All/HostedOrWebAppTest.CtrlClickLink/WebApp
 -CustomTabBarViewBrowserTest.BackToAppButtonIsNotVisibleInOutOfScopePopups
+
+# crbug.com/1473417:
+-All/OfferNotificationBubbleViewPixelBrowserTest.InvokeUi_show_notification_bubble/FreeListingOffer_default
+-All/OfferNotificationBubbleViewPixelBrowserTest.InvokeUi_show_notification_bubble/FreeListingOffer_on_navigation
\ No newline at end of file
diff --git a/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter b/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
index 2fb1604..9963f9a 100644
--- a/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
+++ b/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
@@ -27,6 +27,9 @@
 -BackForwardCachePageLoadMetricsObserverBrowserTest.CumulativeLayoutShiftAfterBackForwardCacheRestore
 -DesktopCaptureApiTest.ChooseDesktopMedia
 -IconLoaderBrowserTest.LoadGroup
+# crbug.com/1473417
+-All/OfferNotificationBubbleViewPixelBrowserTest.InvokeUi_show_notification_bubble/FreeListingOffer_default
+-All/OfferNotificationBubbleViewPixelBrowserTest.InvokeUi_show_notification_bubble/FreeListingOffer_on_navigation
 
 # TODO(https://crbug.com/1084469): fix these tests.
 
diff --git a/testing/buildbot/filters/pixel_tests.filter b/testing/buildbot/filters/pixel_tests.filter
index 896a0c08a..0716e8a 100644
--- a/testing/buildbot/filters/pixel_tests.filter
+++ b/testing/buildbot/filters/pixel_tests.filter
@@ -49,6 +49,7 @@
 InteractionTestUtilBrowserUiTest.CompareScreenshot_*
 LocalCardMigrationBrowserUiTest.*
 NewTabPageTest.*
+OfferNotificationBubbleViewPixelBrowserTest.*
 OneTimePermissionPromptBubbleViewBrowserTest.*
 OutdatedUpgradeBubbleTest.*
 PageInfoBubbleViewAboutThisSiteDialogBrowserTest.*
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index 6ba1ce3..43ad68bd 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1090,7 +1090,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R118-15574.0.0",
+        "cros_img": "brya-release/R118-15585.0.0",
         "name": "chrome_all_tast_tests BRYA_RELEASE_LKGM",
         "shards": 10,
         "tast_expr": "(\"group:mainline\" && \"dep:chrome\" && !\"dep:no_chrome_dcheck\" && !\"dep:lacros\" && !informational)",
@@ -1103,7 +1103,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R118-15574.0.0",
+        "cros_img": "brya-release/R118-15585.0.0",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests BRYA_RELEASE_LKGM",
         "shards": 10,
@@ -1117,7 +1117,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "brya",
-        "cros_img": "brya-release/R118-15574.0.0",
+        "cros_img": "brya-release/R118-15585.0.0",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests BRYA_RELEASE_LKGM",
         "shards": 10,
@@ -1140,7 +1140,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R117-15564.0.0",
+        "cros_img": "jacuzzi-release/R118-15585.0.0",
         "name": "chrome_all_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 10,
         "tast_expr": "(\"group:mainline\" && \"dep:chrome\" && !\"dep:no_chrome_dcheck\" && !\"dep:lacros\" && !informational)",
@@ -1153,7 +1153,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R117-15564.0.0",
+        "cros_img": "jacuzzi-release/R118-15585.0.0",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 10,
@@ -1167,7 +1167,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-release/R117-15564.0.0",
+        "cros_img": "jacuzzi-release/R118-15585.0.0",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 10,
@@ -1190,7 +1190,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R118-15574.0.0",
+        "cros_img": "octopus-release/R118-15585.0.0",
         "name": "chrome_all_tast_tests OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 10,
         "tast_expr": "(\"group:mainline\" && \"dep:chrome\" && !\"dep:no_chrome_dcheck\" && !\"dep:lacros\" && !informational)",
@@ -1236,7 +1236,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "volteer",
-        "cros_img": "volteer-release/R118-15574.0.0",
+        "cros_img": "volteer-release/R118-15585.0.0",
         "name": "chrome_all_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 10,
         "tast_expr": "(\"group:mainline\" && \"dep:chrome\" && !\"dep:no_chrome_dcheck\" && !\"dep:lacros\" && !informational)",
@@ -1249,7 +1249,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "volteer",
-        "cros_img": "volteer-release/R118-15574.0.0",
+        "cros_img": "volteer-release/R118-15585.0.0",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 10,
@@ -1263,7 +1263,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "volteer",
-        "cros_img": "volteer-release/R118-15574.0.0",
+        "cros_img": "volteer-release/R118-15585.0.0",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 10,
@@ -1283,7 +1283,7 @@
     "skylab_tests": [
       {
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R118-15574.0.0",
+        "cros_img": "octopus-release/R118-15585.0.0",
         "name": "lacros_fyi_tast_tests OCTOPUS_RELEASE_LKGM",
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_fyi_tast_tests",
@@ -1323,7 +1323,7 @@
       },
       {
         "cros_board": "octopus",
-        "cros_img": "octopus-release/R118-15574.0.0",
+        "cros_img": "octopus-release/R118-15585.0.0",
         "name": "ozone_unittests OCTOPUS_RELEASE_LKGM",
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -1366,7 +1366,7 @@
     "skylab_tests": [
       {
         "cros_board": "hana",
-        "cros_img": "hana-release/R118-15574.0.0",
+        "cros_img": "hana-release/R118-15585.0.0",
         "name": "lacros_all_tast_tests HANA_RELEASE_LKGM",
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
@@ -1447,7 +1447,7 @@
       },
       {
         "cros_board": "hana",
-        "cros_img": "hana-release/R118-15574.0.0",
+        "cros_img": "hana-release/R118-15585.0.0",
         "name": "ozone_unittests HANA_RELEASE_LKGM",
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -1520,7 +1520,7 @@
       },
       {
         "cros_board": "hana",
-        "cros_img": "hana-release/R118-15574.0.0",
+        "cros_img": "hana-release/R118-15585.0.0",
         "name": "viz_unittests HANA_RELEASE_LKGM",
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
diff --git a/testing/buildbot/tryserver.chromium.chromiumos.json b/testing/buildbot/tryserver.chromium.chromiumos.json
index ec9f313..05d5de9 100644
--- a/testing/buildbot/tryserver.chromium.chromiumos.json
+++ b/testing/buildbot/tryserver.chromium.chromiumos.json
@@ -9,7 +9,7 @@
       {
         "bucket": "chromiumos-image-archive",
         "cros_board": "volteer",
-        "cros_img": "volteer-public/R118-15574.0.0",
+        "cros_img": "volteer-public/R118-15585.0.0",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests VOLTEER_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 980fdbb..0c2b481 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -16,16 +16,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 118.0.5964.0',
+    'description': 'Run with ash-chrome version 118.0.5965.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5964.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v118.0.5965.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v118.0.5964.0',
-          'revision': 'version:118.0.5964.0',
+          'location': 'lacros_version_skew_tests_v118.0.5965.0',
+          'revision': 'version:118.0.5965.0',
         },
       ],
     },
@@ -372,7 +372,7 @@
     'identifier': 'BRYA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'brya',
-      'cros_img': 'brya-release/R118-15574.0.0',
+      'cros_img': 'brya-release/R118-15585.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'shards': 10,
     },
@@ -381,7 +381,7 @@
     'identifier': 'DEDEDE_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'dedede',
-      'cros_img': 'dedede-release/R118-15574.0.0',
+      'cros_img': 'dedede-release/R118-15585.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -410,7 +410,7 @@
     'identifier': 'EVE_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-release/R118-15574.0.0',
+      'cros_img': 'eve-release/R118-15585.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -439,7 +439,7 @@
     'identifier': 'EVE_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-public/R118-15574.0.0',
+      'cros_img': 'eve-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -450,7 +450,7 @@
     'identifier': 'HANA_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'hana',
-      'cros_img': 'hana-release/R118-15574.0.0',
+      'cros_img': 'hana-release/R118-15585.0.0',
     },
   },
   'CROS_HANA_RELEASE_DEV': {
@@ -478,7 +478,7 @@
     'identifier': 'JACUZZI_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-release/R117-15564.0.0',
+      'cros_img': 'jacuzzi-release/R118-15585.0.0',
       'autotest_name': 'tast.lacros-from-gcs',
     },
   },
@@ -500,7 +500,7 @@
     'identifier': 'JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-release/R117-15564.0.0',
+      'cros_img': 'jacuzzi-release/R118-15585.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'shards': 10,
     },
@@ -516,7 +516,7 @@
     'identifier': 'JACUZZI_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R117-15564.0.0',
+      'cros_img': 'jacuzzi-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -524,7 +524,7 @@
     'identifier': 'JACUZZI_CQ_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R117-15564.0.0',
+      'cros_img': 'jacuzzi-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
       'public_builder': 'cros_test_platform_public',
       'public_builder_bucket': 'testplatform-public',
@@ -534,7 +534,7 @@
     'identifier': 'KEVIN64_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'kevin',
-      'cros_img': 'kevin64-public/R118-15574.0.0',
+      'cros_img': 'kevin64-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -550,7 +550,7 @@
     'identifier': 'OCTOPUS_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-public/R118-15574.0.0',
+      'cros_img': 'octopus-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -558,7 +558,7 @@
     'identifier': 'OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-release/R118-15574.0.0',
+      'cros_img': 'octopus-release/R118-15585.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'shards': 10,
     },
@@ -567,7 +567,7 @@
     'identifier': 'OCTOPUS_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-release/R118-15574.0.0',
+      'cros_img': 'octopus-release/R118-15585.0.0',
     },
   },
   'CROS_OCTOPUS_RELEASE_DEV': {
@@ -633,7 +633,7 @@
     'identifier': 'VOLTEER_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'volteer',
-      'cros_img': 'volteer-public/R118-15574.0.0',
+      'cros_img': 'volteer-public/R118-15585.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -677,7 +677,7 @@
     'identifier': 'VOLTEER_RELEASE_LKGM',
     'skylab': {
       'cros_board': 'volteer',
-      'cros_img': 'volteer-release/R118-15574.0.0',
+      'cros_img': 'volteer-release/R118-15585.0.0',
       'autotest_name': 'tast.chrome-from-gcs',
       'shards': 10,
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index ddfc5ca..b59f5f8e 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -8400,6 +8400,22 @@
             ]
         }
     ],
+    "IOSWhatsNewM116": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_Whats_New_M116",
+                    "enable_features": [
+                        "IPH_WhatsNew",
+                        "WhatsNewIOSM116"
+                    ]
+                }
+            ]
+        }
+    ],
     "IdentifiabilityStudy": [
         {
             "platforms": [
@@ -10771,6 +10787,21 @@
             ]
         }
     ],
+    "OrcaDogfoodEnabled": [
+        {
+            "platforms": [
+                "chromeos"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "OrcaDogfood"
+                    ]
+                }
+            ]
+        }
+    ],
     "OriginAgentClusterDefaultEnabled": [
         {
             "platforms": [
@@ -10811,6 +10842,47 @@
             ]
         }
     ],
+    "OutOfProcessNetworkService": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "EnableOOPNS_over_6656_Mb_20230410",
+                    "disable_features": [
+                        "NetworkServiceEmptyOutOfProcess",
+                        "NetworkServiceInProcess2"
+                    ]
+                },
+                {
+                    "name": "EmptyOOPNS_20230705",
+                    "enable_features": [
+                        "NetworkServiceEmptyOutOfProcess",
+                        "NetworkServiceInProcess2"
+                    ]
+                }
+            ]
+        }
+    ],
+    "OutOfProcessNetworkServiceMemoryControls": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Over_6500_mb_20230410",
+                    "params": {
+                        "network_service_oop_threshold_mb": "6656"
+                    },
+                    "enable_features": [
+                        "NetworkServiceOutOfProcessMemoryThreshold"
+                    ]
+                }
+            ]
+        }
+    ],
     "OutOfProcessPrintDriversPrint": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
index e5f2d16..fdc6f021 100644
--- a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
+++ b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
@@ -227,14 +227,14 @@
   // for the browser process to start enforcing timeouts on script execution.
   OnScriptEvaluationStart();
   // Indicates that the worker has started. |thread_id| is the platform
-  // thread id the worker runs on. |fetch_handler_type| represents the fetch
-  // handler type. The type is decided after initial script evaluation, and
-  // it can also represents the fetch event handler does not exist.
-  // |has_hid_event_handlers| represent any HID event handlers and is decided
-  // after initial script evaluation.
+  // thread id the worker runs on. |fetch_handler_type|,
+  // |has_hid_event_handlers|, and |has_usb_event_handlers| are determined
+  // after the initial script evaluation and used by the browser process to
+  // forward the corresponding events to the service worker.
   OnStarted(ServiceWorkerStartStatus status,
             blink.mojom.ServiceWorkerFetchHandlerType fetch_handler_type,
             bool has_hid_event_handlers,
+            bool has_usb_event_handlers,
             int32 thread_id,
             EmbeddedWorkerStartTiming start_timing);
 
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
index bd84703..86ac2d6 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
@@ -75,6 +75,7 @@
   virtual void ResumeEvaluation() = 0;
   virtual mojom::ServiceWorkerFetchHandlerType FetchHandlerType() = 0;
   virtual bool HasHidEventHandlers() = 0;
+  virtual bool HasUsbEventHandlers() = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni
index bd101d5..6fb64d3 100644
--- a/third_party/blink/renderer/bindings/generated_in_core.gni
+++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -524,8 +524,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_predefined_color_space.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_premultiply_alpha.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_premultiply_alpha.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_prevented_back_forward_cache.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_prevented_back_forward_cache.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_private_token_version.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_private_token_version.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_profiler_marker.cc",
@@ -1183,8 +1181,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_node_list.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_node_part.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_node_part.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_not_restored_reasons.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_not_restored_reasons.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_offscreen_canvas.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_offscreen_canvas.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_overscroll_event.cc",
@@ -1657,10 +1653,6 @@
 generated_observable_array_sources_in_core = [
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_observable_array_css_style_sheet.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_observable_array_css_style_sheet.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_observable_array_not_restored_reasons.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_observable_array_not_restored_reasons.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_observable_array_string.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_observable_array_string.h",
 ]
 
 generated_sync_iterator_sources_in_core = [
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni
index 6b31c4c..f72cf4f 100644
--- a/third_party/blink/renderer/bindings/idl_in_core.gni
+++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -688,7 +688,6 @@
   "//third_party/blink/renderer/core/timing/measure_memory/memory_breakdown_entry.idl",
   "//third_party/blink/renderer/core/timing/measure_memory/memory_measurement.idl",
   "//third_party/blink/renderer/core/timing/memory_info.idl",
-  "//third_party/blink/renderer/core/timing/not_restored_reasons.idl",
   "//third_party/blink/renderer/core/timing/performance.idl",
   "//third_party/blink/renderer/core/timing/performance_element_timing.idl",
   "//third_party/blink/renderer/core/timing/performance_entry.idl",
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index e135f19a..d491eba 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2495,17 +2495,6 @@
 
 void Element::ClassAttributeChanged(const AtomicString& new_class_string) {
   DCHECK(HasElementData());
-  if (!element_data_->IsUnique()) {
-    ShareableElementData* shareable_element_data =
-        To<ShareableElementData>(element_data_.Get());
-    if (!shareable_element_data->class_is_dirty() && !InActiveDocument()) {
-      // `element_data` is shared, class related state is up to date, and
-      // this is not in the active document. No additional processing is
-      // necessary (because ClassChangedForElement() does nothing if not
-      // in an active document).
-      return;
-    }
-  }
   ClassStringContent class_string_content_type =
       ClassStringHasClassName(new_class_string);
   const bool should_fold_case = GetDocument().InQuirksMode();
@@ -2524,9 +2513,6 @@
       GetElementData()->ClearClass();
     }
   }
-  if (!element_data_->IsUnique()) {
-    To<ShareableElementData>(element_data_.Get())->SetClassIsDirty(false);
-  }
 }
 
 void Element::UpdateClassList(const AtomicString& old_class_string,
@@ -2589,14 +2575,14 @@
   DCHECK(!element_data_);
 
   if (!attribute_vector.empty()) {
-    if (auto* cache = GetDocument().GetElementDataCache()) {
-      element_data_ = cache->ElementDataWithAttributes(attribute_vector);
-    } else if (attribute_vector.size() <=
-               ShareableElementData::kMaxNumberOfAttributes) {
+    if (GetDocument().GetElementDataCache()) {
+      element_data_ =
+          GetDocument()
+              .GetElementDataCache()
+              ->CachedShareableElementDataWithAttributes(attribute_vector);
+    } else {
       element_data_ =
           ShareableElementData::CreateWithAttributes(attribute_vector);
-    } else {
-      element_data_ = MakeGarbageCollected<UniqueElementData>(attribute_vector);
     }
   }
 
diff --git a/third_party/blink/renderer/core/dom/element_data.cc b/third_party/blink/renderer/core/dom/element_data.cc
index 19c7a6b1..6b7a21c 100644
--- a/third_party/blink/renderer/core/dom/element_data.cc
+++ b/third_party/blink/renderer/core/dom/element_data.cc
@@ -52,31 +52,27 @@
 }
 
 ElementData::ElementData()
-    : bit_field_(IsUniqueFlag::encode(true) | ShareableArraySize::encode(0) |
+    : bit_field_(IsUniqueFlag::encode(true) | ArraySize::encode(0) |
                  PresentationAttributeStyleIsDirty::encode(false) |
                  StyleAttributeIsDirty::encode(false) |
-                 SvgAttributesAreDirty::encode(false) |
-                 ClassIsDirty::encode(true)) {}
+                 SvgAttributesAreDirty::encode(false)) {}
 
 ElementData::ElementData(unsigned array_size)
-    : bit_field_(
-          IsUniqueFlag::encode(false) | ShareableArraySize::encode(array_size) |
-          PresentationAttributeStyleIsDirty::encode(false) |
-          StyleAttributeIsDirty::encode(false) |
-          SvgAttributesAreDirty::encode(false) | ClassIsDirty::encode(true)) {}
+    : bit_field_(IsUniqueFlag::encode(false) | ArraySize::encode(array_size) |
+                 PresentationAttributeStyleIsDirty::encode(false) |
+                 StyleAttributeIsDirty::encode(false) |
+                 SvgAttributesAreDirty::encode(false)) {}
 
 ElementData::ElementData(const ElementData& other, bool is_unique)
     : bit_field_(
           IsUniqueFlag::encode(is_unique) |
-          ShareableArraySize::encode(is_unique ? 0
-                                               : other.Attributes().size()) |
+          ArraySize::encode(is_unique ? 0 : other.Attributes().size()) |
           PresentationAttributeStyleIsDirty::encode(
               other.bit_field_.get<PresentationAttributeStyleIsDirty>()) |
           StyleAttributeIsDirty::encode(
               other.bit_field_.get<StyleAttributeIsDirty>()) |
           SvgAttributesAreDirty::encode(
-              other.bit_field_.get<SvgAttributesAreDirty>()) |
-          ClassIsDirty::encode(other.bit_field_.get<ClassIsDirty>())),
+              other.bit_field_.get<SvgAttributesAreDirty>())),
       class_names_(other.class_names_),
       id_for_style_resolution_(other.id_for_style_resolution_) {
   // NOTE: The inline style is copied by the subclass copy constructor since we
@@ -129,15 +125,13 @@
 ShareableElementData::ShareableElementData(
     const Vector<Attribute, kAttributePrealloc>& attributes)
     : ElementData(attributes.size()) {
-  for (unsigned i = 0; i < bit_field_.get<ShareableArraySize>(); ++i) {
+  for (unsigned i = 0; i < bit_field_.get<ArraySize>(); ++i)
     new (&attribute_array_[i]) Attribute(attributes[i]);
-  }
 }
 
 ShareableElementData::~ShareableElementData() {
-  for (unsigned i = 0; i < bit_field_.get<ShareableArraySize>(); ++i) {
+  for (unsigned i = 0; i < bit_field_.get<ArraySize>(); ++i)
     attribute_array_[i].~Attribute();
-  }
 }
 
 ShareableElementData::ShareableElementData(const UniqueElementData& other)
@@ -148,9 +142,8 @@
     inline_style_ = other.inline_style_->ImmutableCopyIfNeeded();
   }
 
-  for (unsigned i = 0; i < bit_field_.get<ShareableArraySize>(); ++i) {
+  for (unsigned i = 0; i < bit_field_.get<ArraySize>(); ++i)
     new (&attribute_array_[i]) Attribute(other.attribute_vector_.at(i));
-  }
 }
 
 ShareableElementData* ShareableElementData::CreateWithAttributes(
@@ -191,10 +184,6 @@
       *this);
 }
 
-UniqueElementData::UniqueElementData(
-    const Vector<Attribute, kAttributePrealloc>& attrs)
-    : attribute_vector_(attrs) {}
-
 void UniqueElementData::TraceAfterDispatch(blink::Visitor* visitor) const {
   visitor->Trace(presentation_attribute_style_);
   ElementData::TraceAfterDispatch(visitor);
diff --git a/third_party/blink/renderer/core/dom/element_data.h b/third_party/blink/renderer/core/dom/element_data.h
index 78b9204d..cddb64b 100644
--- a/third_party/blink/renderer/core/dom/element_data.h
+++ b/third_party/blink/renderer/core/dom/element_data.h
@@ -89,24 +89,15 @@
   void Trace(Visitor*) const;
 
  protected:
-  static constexpr size_t kShareableArraySizeBits = 27;
-
   using BitField = WTF::ConcurrentlyReadBitField<uint32_t>;
   using IsUniqueFlag =
       BitField::DefineFirstValue<bool, 1, WTF::BitFieldValueConstness::kConst>;
-  // This is used solely by ShareableElementData. It gives the number of
-  // elements in the array.
-  using ShareableArraySize =
-      IsUniqueFlag::DefineNextValue<uint32_t,
-                                    kShareableArraySizeBits,
-                                    WTF::BitFieldValueConstness::kConst>;
-  using PresentationAttributeStyleIsDirty =
-      ShareableArraySize::DefineNextValue<bool, 1>;
+  using ArraySize = IsUniqueFlag::
+      DefineNextValue<uint32_t, 28, WTF::BitFieldValueConstness::kConst>;
+  using PresentationAttributeStyleIsDirty = ArraySize::DefineNextValue<bool, 1>;
   using StyleAttributeIsDirty =
       PresentationAttributeStyleIsDirty::DefineNextValue<bool, 1>;
   using SvgAttributesAreDirty = StyleAttributeIsDirty::DefineNextValue<bool, 1>;
-  // Used by ShareableElementData. Tracks if the `class` needs to be calculated.
-  using ClassIsDirty = SvgAttributesAreDirty::DefineNextValue<bool, 1>;
 
   ElementData();
   explicit ElementData(unsigned array_size);
@@ -121,7 +112,6 @@
   bool svg_attributes_are_dirty() const {
     return bit_field_.get<SvgAttributesAreDirty>();
   }
-  bool class_is_dirty() const { return bit_field_.get<ClassIsDirty>(); }
 
   // Following 3 fields are meant to be mutable and can change even when const.
   void SetPresentationAttributeStyleIsDirty(
@@ -138,9 +128,6 @@
     const_cast<BitField*>(&bit_field_)
         ->set<SvgAttributesAreDirty>(svg_attributes_are_dirty);
   }
-  void SetClassIsDirty(bool value) const {
-    const_cast<BitField*>(&bit_field_)->set<ClassIsDirty>(value);
-  }
 
   BitField bit_field_;
 
@@ -172,9 +159,6 @@
 // duplicate sets of attributes (ex. the same classes).
 class ShareableElementData final : public ElementData {
  public:
-  // Maximum number of attributes this can hold.
-  static constexpr size_t kMaxNumberOfAttributes = 2 ^ kShareableArraySizeBits;
-
   static ShareableElementData* CreateWithAttributes(
       const Vector<Attribute, kAttributePrealloc>&);
 
@@ -217,8 +201,7 @@
 
   UniqueElementData();
   explicit UniqueElementData(const ShareableElementData&);
-  UniqueElementData(const UniqueElementData&);
-  explicit UniqueElementData(const Vector<Attribute, kAttributePrealloc>&);
+  explicit UniqueElementData(const UniqueElementData&);
 
   void TraceAfterDispatch(blink::Visitor*) const;
 
@@ -251,8 +234,7 @@
 }
 
 inline AttributeCollection ShareableElementData::Attributes() const {
-  return AttributeCollection(attribute_array_,
-                             bit_field_.get<ShareableArraySize>());
+  return AttributeCollection(attribute_array_, bit_field_.get<ArraySize>());
 }
 
 inline AttributeCollection UniqueElementData::Attributes() const {
diff --git a/third_party/blink/renderer/core/dom/element_data_cache.cc b/third_party/blink/renderer/core/dom/element_data_cache.cc
index 9dcd986..d2da8030 100644
--- a/third_party/blink/renderer/core/dom/element_data_cache.cc
+++ b/third_party/blink/renderer/core/dom/element_data_cache.cc
@@ -69,7 +69,8 @@
                          attributes.size() * sizeof(Attribute));
 }
 
-ElementData* ElementDataCache::ElementDataWithAttributes(
+ShareableElementData*
+ElementDataCache::CachedShareableElementDataWithAttributes(
     const Vector<Attribute, kAttributePrealloc>& attributes) {
   DCHECK(!attributes.empty());
 
@@ -81,13 +82,8 @@
   if (it->value && !HasSameAttributes(attributes, *it->value))
     return ShareableElementData::CreateWithAttributes(attributes);
 
-  if (!it->value) {
-    if (attributes.size() < ShareableElementData::kMaxNumberOfAttributes) {
-      it->value = ShareableElementData::CreateWithAttributes(attributes);
-    } else {
-      return MakeGarbageCollected<UniqueElementData>(attributes);
-    }
-  }
+  if (!it->value)
+    it->value = ShareableElementData::CreateWithAttributes(attributes);
 
   return it->value.Get();
 }
diff --git a/third_party/blink/renderer/core/dom/element_data_cache.h b/third_party/blink/renderer/core/dom/element_data_cache.h
index 03c0f915a..892ba615 100644
--- a/third_party/blink/renderer/core/dom/element_data_cache.h
+++ b/third_party/blink/renderer/core/dom/element_data_cache.h
@@ -34,17 +34,13 @@
 
 namespace blink {
 
-class ElementData;
 class ShareableElementData;
 
 class ElementDataCache final : public GarbageCollected<ElementDataCache> {
  public:
   ElementDataCache();
 
-  // Returns an ElementData representing the specified attributes. This prefers
-  // returning a ShareableElementData, but in some cases returns an
-  // ElementData.
-  ElementData* ElementDataWithAttributes(
+  ShareableElementData* CachedShareableElementDataWithAttributes(
       const Vector<Attribute, kAttributePrealloc>&);
 
   void Trace(Visitor*) const;
diff --git a/third_party/blink/renderer/core/timing/build.gni b/third_party/blink/renderer/core/timing/build.gni
index 6482a03..7a88e74 100644
--- a/third_party/blink/renderer/core/timing/build.gni
+++ b/third_party/blink/renderer/core/timing/build.gni
@@ -26,8 +26,6 @@
   "measure_memory/measure_memory_controller.h",
   "memory_info.cc",
   "memory_info.h",
-  "not_restored_reasons.cc",
-  "not_restored_reasons.h",
   "performance.cc",
   "performance.h",
   "performance_element_timing.cc",
diff --git a/third_party/blink/renderer/core/timing/not_restored_reasons.cc b/third_party/blink/renderer/core/timing/not_restored_reasons.cc
deleted file mode 100644
index 801e54c..0000000
--- a/third_party/blink/renderer/core/timing/not_restored_reasons.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/timing/not_restored_reasons.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
-#include "third_party/blink/renderer/platform/wtf/casting.h"
-
-namespace blink {
-
-NotRestoredReasons::NotRestoredReasons(String prevented,
-                                       String src,
-                                       String id,
-                                       String name,
-                                       String url,
-                                       Vector<String>* reasons,
-                                       HeapVector<NotRestoredReasons>* children)
-    : prevented_(prevented), src_(src), id_(id), name_(name), url_(url) {
-  if (reasons) {
-    reasons_ =
-        MakeGarbageCollected<V8ObservableArrayString>(this, nullptr, nullptr);
-    for (String reason : *reasons) {
-      reasons_->push_back(reason);
-    }
-  }
-  if (children) {
-    children_ = MakeGarbageCollected<V8ObservableArrayNotRestoredReasons>(
-        this, nullptr, nullptr);
-    for (NotRestoredReasons& child : *children) {
-      children_->push_back(child);
-    }
-  }
-}
-
-void NotRestoredReasons::Trace(Visitor* visitor) const {
-  visitor->Trace(reasons_);
-  visitor->Trace(children_);
-  ScriptWrappable::Trace(visitor);
-}
-
-NotRestoredReasons::NotRestoredReasons(const NotRestoredReasons& other)
-    : prevented_(other.prevented_),
-      src_(other.src_),
-      id_(other.id_),
-      name_(other.name_),
-      url_(other.url_),
-      reasons_(other.reasons_),
-      children_(other.children_) {}
-
-ScriptValue NotRestoredReasons::toJSON(ScriptState* script_state) const {
-  V8ObjectBuilder builder(script_state);
-
-  builder.AddString("preventedBackForwardCache", preventedBackForwardCache());
-  builder.AddStringOrNull("src", src());
-  builder.AddStringOrNull("id", id());
-  builder.AddStringOrNull("url", url());
-  builder.AddStringOrNull("name", name());
-  if (!url().IsNull()) {
-    // Same origin details are present.
-    Vector<AtomicString> reason_strings;
-    for (const auto& reason : *reasons()) {
-      reason_strings.push_back(reason);
-    }
-    builder.Add("reasons", reason_strings);
-
-    Vector<v8::Local<v8::Value>> children_result;
-    for (Member<NotRestoredReasons> child : *children()) {
-      children_result.push_back(child->toJSON(script_state).V8Value());
-    }
-    builder.Add("children", children_result);
-  } else {
-    // For cross-origin iframes, reasons, children and url should always be
-    // null.
-    builder.AddNull("reasons");
-    builder.AddNull("children");
-  }
-
-  return builder.GetScriptValue();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/timing/not_restored_reasons.h b/third_party/blink/renderer/core/timing/not_restored_reasons.h
deleted file mode 100644
index 38064fb..0000000
--- a/third_party/blink/renderer/core/timing/not_restored_reasons.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_NOT_RESTORED_REASONS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_NOT_RESTORED_REASONS_H_
-
-#include "third_party/blink/public/mojom/back_forward_cache_not_restored_reasons.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_observable_array_not_restored_reasons.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_observable_array_string.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class CORE_EXPORT NotRestoredReasons : public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  // Make this protected. Always create with a Build.. method
-  explicit NotRestoredReasons(String prevented,
-                              String src,
-                              String id,
-                              String name,
-                              String url,
-                              Vector<String>* reasons,
-                              HeapVector<NotRestoredReasons>* children);
-
-  NotRestoredReasons(const NotRestoredReasons&);
-
-  const String preventedBackForwardCache() const { return prevented_; }
-
-  const String src() const { return src_; }
-
-  const String id() const { return id_; }
-
-  const String name() const { return name_; }
-
-  const String url() const { return url_; }
-
-  const V8ObservableArrayString* reasons() const { return reasons_; }
-
-  const V8ObservableArrayNotRestoredReasons* children() const {
-    return children_;
-  }
-
-  ScriptValue toJSON(ScriptState* script_state) const;
-
-  void Trace(Visitor* visitor) const override;
-
- private:
-  String prevented_;
-  String src_;
-  String id_;
-  String name_;
-  String url_;
-  Member<V8ObservableArrayString> reasons_;
-  Member<V8ObservableArrayNotRestoredReasons> children_;
-};
-
-}  // namespace blink
-
-#endif  // #define
-        // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_NOT_RESTORED_REASONS_H_
diff --git a/third_party/blink/renderer/core/timing/not_restored_reasons.idl b/third_party/blink/renderer/core/timing/not_restored_reasons.idl
deleted file mode 100644
index a81dd0f..0000000
--- a/third_party/blink/renderer/core/timing/not_restored_reasons.idl
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://github.com/WICG/bfcache-not-restored-reason/blob/main/NotRestoredReason.md
-
-enum PreventedBackForwardCache {
-    "yes",
-    "no",
-    "masked"
-};
-
-[
-    Exposed=Window,
-    RuntimeEnabled=BackForwardCacheNotRestoredReasons
-] interface NotRestoredReasons {
-  readonly attribute PreventedBackForwardCache preventedBackForwardCache;
-  readonly attribute DOMString? src;
-  readonly attribute DOMString? id;
-  readonly attribute DOMString? name;
-  readonly attribute DOMString? url;
-  readonly attribute ObservableArray<DOMString>? reasons;
-  readonly attribute ObservableArray<NotRestoredReasons>? children;
-  [CallWith=ScriptState] object toJSON();
-};
\ No newline at end of file
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index 5875fdf..59b78cc 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -284,13 +284,58 @@
   return loadEventEnd();
 }
 
-NotRestoredReasons* PerformanceNavigationTiming::notRestoredReasons() const {
+ScriptValue PerformanceNavigationTiming::notRestoredReasons(
+    ScriptState* script_state) const {
   DocumentLoader* loader = GetDocumentLoader();
   if (!loader || !loader->GetFrame()->IsOutermostMainFrame()) {
-    return nullptr;
+    return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
-  return BuildNotRestoredReasons(loader->GetFrame()->GetNotRestoredReasons());
+  // TODO(crbug.com/1370954): Save NotRestoredReasons in Document instead of
+  // Frame.
+  return NotRestoredReasonsBuilder(script_state,
+                                   loader->GetFrame()->GetNotRestoredReasons());
+}
+
+ScriptValue PerformanceNavigationTiming::NotRestoredReasonsBuilder(
+    ScriptState* script_state,
+    const mojom::blink::BackForwardCacheNotRestoredReasonsPtr& reasons) const {
+  if (!reasons) {
+    return ScriptValue::CreateNull(script_state->GetIsolate());
+  }
+  V8ObjectBuilder builder(script_state);
+  switch (reasons->blocked) {
+    case mojom::blink::BFCacheBlocked::kYes:
+    case mojom::blink::BFCacheBlocked::kNo:
+      builder.AddBoolean(
+          "blocked", reasons->blocked == mojom::blink::BFCacheBlocked::kYes);
+      break;
+    case mojom::blink::BFCacheBlocked::kMasked:
+      // |blocked| can be null when masking the value.
+      builder.AddNull("blocked");
+      break;
+  }
+  builder.AddStringOrNull("src", AtomicString(reasons->src));
+  builder.AddStringOrNull("id", AtomicString(reasons->id));
+  builder.AddStringOrNull("name", AtomicString(reasons->name));
+  Vector<AtomicString> reason_strings;
+  Vector<v8::Local<v8::Value>> children_result;
+  if (reasons->same_origin_details) {
+    builder.AddString("url", AtomicString(reasons->same_origin_details->url));
+    for (const auto& reason : reasons->same_origin_details->reasons) {
+      reason_strings.push_back(reason);
+    }
+    for (const auto& child : reasons->same_origin_details->children) {
+      children_result.push_back(
+          NotRestoredReasonsBuilder(script_state, child).V8Value());
+    }
+  } else {
+    // For cross-origin iframes, url should always be null.
+    builder.AddNull("url");
+  }
+  builder.Add("reasons", reason_strings);
+  builder.Add("children", children_result);
+  return builder.GetScriptValue();
 }
 
 AtomicString PerformanceNavigationTiming::systemEntropy() const {
@@ -315,51 +360,6 @@
       CrossOriginIsolatedCapability());
 }
 
-NotRestoredReasons* PerformanceNavigationTiming::BuildNotRestoredReasons(
-    const mojom::blink::BackForwardCacheNotRestoredReasonsPtr& nrr) const {
-  if (!nrr) {
-    return nullptr;
-  }
-
-  String blocked;
-  switch (nrr->blocked) {
-    case mojom::blink::BFCacheBlocked::kYes:
-      blocked = "yes";
-      break;
-    case mojom::blink::BFCacheBlocked::kNo:
-      blocked = "no";
-      break;
-    case mojom::blink::BFCacheBlocked::kMasked:
-      blocked = "masked";
-      break;
-  }
-  String url;
-  Vector<String> reasons;
-  HeapVector<NotRestoredReasons> children;
-  if (nrr->same_origin_details) {
-    url = nrr->same_origin_details->url;
-    for (const auto& reason : nrr->same_origin_details->reasons) {
-      reasons.push_back(reason);
-    }
-    for (const auto& child : nrr->same_origin_details->children) {
-      NotRestoredReasons* nrr_child = BuildNotRestoredReasons(child);
-      // Reasons in children vector should never be null.
-      CHECK(nrr_child);
-      children.push_back(*nrr_child);
-    }
-  }
-
-  NotRestoredReasons* not_restored_reasons =
-      MakeGarbageCollected<NotRestoredReasons>(
-          /*prevented_back_forward_cache=*/blocked,
-          /*src=*/nrr->src,
-          /*id=*/nrr->id,
-          /*name=*/nrr->name, /*url=*/url,
-          nrr->same_origin_details ? &reasons : nullptr,
-          nrr->same_origin_details ? &children : nullptr);
-  return not_restored_reasons;
-}
-
 void PerformanceNavigationTiming::BuildJSONValue(
     V8ObjectBuilder& builder) const {
   PerformanceResourceTiming::BuildJSONValue(builder);
@@ -381,7 +381,8 @@
 
   if (RuntimeEnabledFeatures::BackForwardCacheNotRestoredReasonsEnabled(
           ExecutionContext::From(builder.GetScriptState()))) {
-    builder.Add("notRestoredReasons", notRestoredReasons());
+    builder.Add("notRestoredReasons",
+                notRestoredReasons(builder.GetScriptState()));
     ExecutionContext::From(builder.GetScriptState())
         ->CountUse(WebFeature::kBackForwardCacheNotRestoredReasons);
   }
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.h b/third_party/blink/renderer/core/timing/performance_navigation_timing.h
index 753bb6c..0c20f6c 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.h
@@ -11,7 +11,6 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/timing/not_restored_reasons.h"
 #include "third_party/blink/renderer/core/timing/performance_resource_timing.h"
 
 namespace blink {
@@ -50,7 +49,7 @@
   DOMHighResTimeStamp loadEventEnd() const;
   AtomicString type() const;
   uint16_t redirectCount() const;
-  NotRestoredReasons* notRestoredReasons() const;
+  ScriptValue notRestoredReasons(ScriptState* script_state) const;
   AtomicString systemEntropy() const;
   DOMHighResTimeStamp criticalCHRestart(ScriptState* script_state) const;
 
@@ -81,7 +80,8 @@
 
   bool AllowRedirectDetails() const;
 
-  NotRestoredReasons* BuildNotRestoredReasons(
+  ScriptValue NotRestoredReasonsBuilder(
+      ScriptState* script_state,
       const mojom::blink::BackForwardCacheNotRestoredReasonsPtr& reasons) const;
 };
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.idl b/third_party/blink/renderer/core/timing/performance_navigation_timing.idl
index b3ec336..053c7ec 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.idl
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.idl
@@ -30,7 +30,7 @@
     readonly attribute DOMHighResTimeStamp loadEventEnd;
     readonly attribute NavigationTimingType type;
     readonly attribute unsigned short redirectCount;
-    [RuntimeEnabled=BackForwardCacheNotRestoredReasons] readonly attribute NotRestoredReasons? notRestoredReasons;
+    [RuntimeEnabled=BackForwardCacheNotRestoredReasons, CallWith=ScriptState] readonly attribute object? notRestoredReasons;
     [RuntimeEnabled=PerformanceNavigateSystemEntropy] readonly attribute NavigationEntropy systemEntropy;
     [CallWith=ScriptState] readonly attribute DOMHighResTimeStamp criticalCHRestart;
     [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
diff --git a/third_party/blink/renderer/modules/service_worker/BUILD.gn b/third_party/blink/renderer/modules/service_worker/BUILD.gn
index 28f645a..6a4255d0 100644
--- a/third_party/blink/renderer/modules/service_worker/BUILD.gn
+++ b/third_party/blink/renderer/modules/service_worker/BUILD.gn
@@ -77,6 +77,7 @@
     "//third_party/blink/renderer/modules/content_index:content_index",
     "//third_party/blink/renderer/modules/cookie_store:cookie_store",
     "//third_party/blink/renderer/modules/hid:hid",
+    "//third_party/blink/renderer/modules/webusb:webusb",
     "//third_party/blink/renderer/modules/notifications:notifications",
     "//third_party/blink/renderer/modules/exported:exported",
     "//third_party/blink/renderer/modules/payments:payments",
diff --git a/third_party/blink/renderer/modules/service_worker/DEPS b/third_party/blink/renderer/modules/service_worker/DEPS
index 8c5a3b01..bf09fee 100644
--- a/third_party/blink/renderer/modules/service_worker/DEPS
+++ b/third_party/blink/renderer/modules/service_worker/DEPS
@@ -11,6 +11,7 @@
     "+third_party/blink/renderer/modules/hid/hid.h",
     "+third_party/blink/renderer/modules/modules_export.h",
     "+third_party/blink/renderer/modules/service_worker",
+    "+third_party/blink/renderer/modules/webusb/usb.h",
     "+third_party/liburlpattern",
 ]
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 726dac1..8dc02ace 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -130,6 +130,7 @@
 #include "third_party/blink/renderer/modules/service_worker/service_worker_window_client.h"
 #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
 #include "third_party/blink/renderer/modules/service_worker/web_service_worker_fetch_context_impl.h"
+#include "third_party/blink/renderer/modules/webusb/usb.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/source_location.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
@@ -2699,6 +2700,11 @@
   return hid ? hid->HasEventListeners() : false;
 }
 
+bool ServiceWorkerGlobalScope::HasUsbEventHandlers() {
+  USB* usb = Supplement<NavigatorBase>::From<USB>(*navigator());
+  return usb ? usb->HasEventListeners() : false;
+}
+
 bool ServiceWorkerGlobalScope::SetAttributeEventListener(
     const AtomicString& event_type,
     EventListener* listener) {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index c2b0316..08f73b2 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -334,6 +334,8 @@
 
   bool HasHidEventHandlers();
 
+  bool HasUsbEventHandlers();
+
   // EventTarget
   bool SetAttributeEventListener(const AtomicString& event_type,
                                  EventListener* listener) override;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index 7a49d9b..a801ab0 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -306,6 +306,10 @@
   return WorkerGlobalScope()->HasHidEventHandlers();
 }
 
+bool ServiceWorkerGlobalScopeProxy::HasUsbEventHandlers() {
+  return WorkerGlobalScope()->HasUsbEventHandlers();
+}
+
 WebServiceWorkerContextClient& ServiceWorkerGlobalScopeProxy::Client() const {
   DCHECK(client_);
   return *client_;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
index 2a4ca0fdf..8173fc0 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -107,6 +107,7 @@
   void ResumeEvaluation() override;
   mojom::blink::ServiceWorkerFetchHandlerType FetchHandlerType() override;
   bool HasHidEventHandlers() override;
+  bool HasUsbEventHandlers() override;
 
   // WorkerReportingProxy overrides:
   void CountFeature(WebFeature) override;
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
index 13bd37dc..3cd1d76 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
+++ b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
@@ -146,3 +146,8 @@
 crbug.com/1090628 external/wpt/html/browsers/windows/iframe-cross-origin-scaled-print.sub.html [ Pass ]
 
 crbug.com/1444753 http/tests/inspector-protocol/tracing/prerender.js [ Skip ]
+
+# Re-enable after new baselines are generated
+crbug.com/1456636 [ Linux ] virtual/view-transition-wide-gamut/view-transition/parent-transition-cancels-child.html [ Failure ]  # Reftest image failure
+crbug.com/1456636 [ Linux ] virtual/view-transition-mpa-serialization/view-transition/parent-transition-cancels-child.html [ Failure ]  # Reftest image failure
+crbug.com/1456636 [ Linux ] virtual/view-transition/view-transition/parent-transition-cancels-child.html [ Failure ]  # Reftest image failure
diff --git a/third_party/blink/web_tests/FlagExpectations/highdpi b/third_party/blink/web_tests/FlagExpectations/highdpi
index 9f7556e..5f3381f 100644
--- a/third_party/blink/web_tests/FlagExpectations/highdpi
+++ b/third_party/blink/web_tests/FlagExpectations/highdpi
@@ -447,3 +447,6 @@
 
 # ====== New tests from wpt-importer added here ======
 crbug.com/626703 virtual/view-transition/external/wpt/css/css-view-transitions/capture-with-opacity-zero-child.html [ Failure ]
+
+# Re-enable after new baselines are generated
+crbug.com/1456636 [ Linux ] virtual/view-transition/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html [ Failure ]  # Reftest image failure
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index c1d7c59..77ccc33d 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6777,3 +6777,8 @@
 crbug.com/1470610 http/tests/devtools/application-panel/resources-panel-resource-preview.js [ Failure Pass ]
 crbug.com/1470610 http/tests/devtools/application-panel/resources-panel-selection-on-reload.js [ Failure Pass ]
 crbug.com/1470610 http/tests/devtools/application-panel/resources-panel-websql.js [ Failure Pass ]
+
+# Re-enable after new baselines are generated
+crbug.com/1456636 [ Linux ] virtual/view-transition/view-transition/parent-transition-cancels-child.html [ Failure ]  # Reftest image failure
+crbug.com/1456636 [ Linux ] virtual/view-transition-wide-gamut/view-transition/parent-transition-cancels-child.html [ Failure ]  # Reftest image failure
+crbug.com/1456636 [ Linux ] virtual/view-transition-mpa-serialization/view-transition/parent-transition-cancels-child.html [ Failure ]  # Reftest image failure
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index ab5ebf1..6e2965c 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -190103,6 +190103,19 @@
         {}
        ]
       ],
+      "text-indent-overflow.html": [
+       "c8678bf8aa85513a2d883341dd6bde7d53380ec2",
+       [
+        null,
+        [
+         [
+          "/css/css-text/text-indent/reference/text-indent-overflow-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "text-indent-percentage-001.xht": [
        "6da26308b266e6d1574d78238f9d12cf5a404b25",
        [
@@ -190168,6 +190181,19 @@
         {}
        ]
       ],
+      "text-indent-text-align-end.html": [
+       "df37463ae7b04a06c3267395df1d9aafa9fa3356",
+       [
+        null,
+        [
+         [
+          "/css/css-text/text-indent/reference/text-indent-text-align-end-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "text-indent-with-absolute-pos-child.html": [
        "16a6deb4769d444c88f95e1018efc5144a327f1d",
        [
@@ -264887,6 +264913,19 @@
      },
      "forms": {
       "the-input-element": {
+       "auto-direction-dynamic.html": [
+        "68ea51185c07833a8cd197f35cbcd6c5ee9c184a",
+        [
+         null,
+         [
+          [
+           "/html/semantics/forms/the-input-element/auto-direction-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
        "image01.html": [
         "e9028dceec736da67b8c8814cb103cfecbc518a0",
         [
@@ -325083,7 +325122,7 @@
        []
       ],
       "grid-template-shorthand-valid-expected.txt": [
-       "db160d9fb4793c50af8d16e029c0dca0d5ff26f1",
+       "b34193d32fc699acd1c2072a60dcf4adf7ead9d2",
        []
       ],
       "grid-template-shorthand-valid.html.ini": [
@@ -344387,6 +344426,10 @@
         "faa6adc4dca1b68585d06bece5d8982c18377180",
         []
        ],
+       "text-indent-overflow-ref.html": [
+        "578cc760677e7c3540b307254f052420ff00a587",
+        []
+       ],
        "text-indent-percentage-001-ref.xht": [
         "5b065d1db7ac1e399668e8588727be09922bf62b",
         []
@@ -344399,6 +344442,10 @@
         "4d85456dd172b108486b51eedddb687209a30b2a",
         []
        ],
+       "text-indent-text-align-end-ref.html": [
+        "c4619235d395cd2e10ea3e50c784880048508812",
+        []
+       ],
        "text-indent-with-absolute-pos-child-ref.html": [
         "e5feb2c7f98dcf426a7874ca2b57e0d15f18ffe3",
         []
@@ -367732,7 +367779,7 @@
       []
      ],
      "empty-elements-insertion-expected.txt": [
-      "74501eab59da19551d8500949035f9ab32db747e",
+      "6bff876fb8662b5106e6e1f5f71793df0bfe2c00",
       []
      ],
      "empty-elements-insertion.html.ini": [
@@ -384011,6 +384058,10 @@
         "142c407d10ddc21eefa546e8e7e81823e01ed5ce",
         []
        ],
+       "dir-slots-directionality.tentative-expected.txt": [
+        "73de097c9abd85cf24c816733c1d49bc15d25023",
+        []
+       ],
        "dir_auto-EN-L-ref.html": [
         "de6e13b3a3221f6054e387eb76525673bc1201f9",
         []
@@ -392593,6 +392644,10 @@
        }
       },
       "the-input-element": {
+       "auto-direction-ref.html": [
+        "675ba509144515a44e06f39dd1ac727b4a2d2bc6",
+        []
+       ],
        "checkable-active-onblur-with-click-expected.txt": [
         "1eac700b1b5f75697a4abb8b76acf2b031f81ebd",
         []
@@ -392716,7 +392771,7 @@
         ]
        },
        "selection-pointer-expected.txt": [
-        "92255d9932e6a679b84e2b8f9100dc6183f29e47",
+        "a46cb70594b81466ca0c856428b12ce23e940d36",
         []
        ],
        "selection-pointer.html.ini": [
@@ -401244,10 +401299,6 @@
      "f415ca94798e0e262f455d1c3772cccd07ffd862",
      []
     ],
-    "first-paint-equals-lcp-text.html.ini": [
-     "78cff02ad8a1c6e7b12afe72d222f2b292a30f14",
-     []
-    ],
     "image-TAO.sub.html.ini": [
      "ffc0f86674bbf55252e43843ad005561ccfa19b3",
      []
@@ -482030,7 +482081,7 @@
        ]
       ],
       "grid-template-shorthand-valid.html": [
-       "d5ae75e74e504c47ac7fe2dca707a1a1ab269644",
+       "0830ea72d5cd3293b8db1e685c3ffb07d8be1630",
        [
         null,
         {}
@@ -578803,7 +578854,7 @@
         ]
        ],
        "dir-slots-directionality.tentative.html": [
-        "1f0dc07f8ef5c1ef5a2bf2ee955285ec33f2d639",
+        "5e8cedb9c156f7c3f83d6e22af46e31cc1ed5874",
         [
          null,
          {}
@@ -619614,9 +619665,9 @@
      ]
     ],
     "pointerevent_attributes_nohover_pointers.html": [
-     "374279135d0c182e605cb7e661d89b1a8e27ca6a",
+     "d501ae0afd45612f5bad13d08cdd7cb2646a38d9",
      [
-      "pointerevents/pointerevent_attributes_nohover_pointers.html?touch",
+      null,
       {
        "testdriver": true
       }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-shorthand-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-shorthand-valid-expected.txt
index db160d9..b34193d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-shorthand-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-shorthand-valid-expected.txt
@@ -27,6 +27,7 @@
 FAIL e.style['grid-template'] = "\"a\" [a] \"b\"" should set the property value assert_equals: serialization should be canonical expected "\"a\" [a] \"b\"" but got "\"a\" auto [a] \"b\" auto"
 PASS e.style['grid-template'] = "\"a\" / 0" should set the property value
 PASS e.style['grid-template'] = "\"a\" 10px / 10px" should set the property value
+PASS e.style['grid-template'] = "\"a\" calc(100% - 10px) / calc(10px)" should set the property value
 FAIL e.style['grid-template'] = "\"a\" [a] \"b\" 10px" should set the property value assert_equals: serialization should be canonical expected "\"a\" [a] \"b\" 10px" but got "\"a\" auto [a] \"b\" 10px"
 FAIL e.style['grid-template'] = "\"a\" [a] \"b\" 10px [a]" should set the property value assert_equals: serialization should be canonical expected "\"a\" [a] \"b\" 10px [a]" but got "\"a\" auto [a] \"b\" 10px [a]"
 FAIL e.style['grid-template'] = "\"a\" [a] [a] \"b\" 10px" should set the property value assert_equals: serialization should be canonical expected "\"a\" [a a] \"b\" 10px" but got "\"a\" auto [a a] \"b\" 10px"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-shorthand-valid.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-shorthand-valid.html
index d5ae75e7..0830ea72 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-shorthand-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-template-shorthand-valid.html
@@ -41,6 +41,7 @@
 test_valid_value("grid-template", '"a" [a] "b"');
 test_valid_value("grid-template", '"a" / 0', '"a" / 0px');
 test_valid_value("grid-template", '"a" 10px / 10px');
+test_valid_value("grid-template", '"a" calc(100% - 10px) / calc(10px)');
 test_valid_value("grid-template", '"a" [a] "b" 10px');
 test_valid_value("grid-template", '"a" [a] "b" 10px [a]');
 test_valid_value("grid-template", '"a" [a] [a] "b" 10px', '"a" [a a] "b" 10px');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/reference/text-indent-overflow-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/reference/text-indent-overflow-ref.html
new file mode 100644
index 0000000..578cc76
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/reference/text-indent-overflow-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: text-indent causing text to overflow container</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#text-indent-property">
+<style>
+.container {
+  border: solid;
+  width: 200px;
+}
+
+.content {
+  display: inline-block;
+  width: 50px;
+  height: 20px;
+  background: green;
+}
+</style>
+
+<p>Test passes if the green square is positioned just past the content edge of the box.</p>
+
+<div class="container">
+  <span style="margin-left: 200px;"><div class="content"></div></span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/reference/text-indent-text-align-end-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/reference/text-indent-text-align-end-ref.html
new file mode 100644
index 0000000..c461923
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/reference/text-indent-text-align-end-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: text-indent with text-align: end</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#text-indent-property">
+<meta name="assert" content="Percentages in text-indent refer to width of the element's content box">
+<style>
+.container {
+  border: solid;
+  width: 200px;
+  text-align: end;
+}
+
+.content {
+  display: inline-block;
+  width: 50px;
+  height: 20px;
+  background: green;
+}
+</style>
+
+<p>Test passes if the green square is positioned against the right edge of the box.</p>
+
+<div class="container">
+  <div class="content"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/text-indent-overflow.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/text-indent-overflow.html
new file mode 100644
index 0000000..c8678bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/text-indent-overflow.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: text-indent causing text to overflow container</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#text-indent-property">
+<link rel="match" href="reference/text-indent-overflow-ref.html">
+<meta name="assert" content="Percentages in text-indent refer to width of the element's content box">
+<style>
+.container {
+  border: solid;
+  width: 200px;
+  text-indent: 200px;
+  text-align: right;
+}
+
+.content {
+  display: inline-block;
+  width: 50px;
+  height: 20px;
+  background: green;
+}
+</style>
+
+<p>Test passes if the green square is positioned just past the content edge of the box.</p>
+
+<!--
+  In this case the `text-indent` is as wide as the container, but should be
+  handled like the linebox had a large left margin, causing the content to
+  overflow the container.
+-->
+<div class="container">
+  <div class="content"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/text-indent-text-align-end.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/text-indent-text-align-end.html
new file mode 100644
index 0000000..df37463
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-indent/text-indent-text-align-end.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: text-indent with text-align: end</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#text-indent-property">
+<link rel="match" href="reference/text-indent-text-align-end-ref.html">
+<meta name="assert" content="Percentages in text-indent refer to width of the element's content box">
+<style>
+.container {
+  border: solid;
+  width: 200px;
+  text-indent: 50px;
+  text-align: end;
+}
+
+.content {
+  display: inline-block;
+  width: 50px;
+  height: 20px;
+  background: green;
+}
+</style>
+
+<p>Test passes if the green square is positioned against the right edge of the box.</p>
+
+<!--
+  In this case the `text-indent` doesn't affect the positioning of the content
+  when text-align positions it further than the indent does.
+-->
+<div class="container">
+  <div class="content"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js
index 811fa51..b3c029d4 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-attributes.tentative.window.js
@@ -38,20 +38,20 @@
   await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false);
   await assertNotRestoredReasonsEquals(
       rc1,
-      /*preventedBackForwardCache=*/ "yes",
+      /*blocked=*/ true,
       /*url=*/ rc1_url,
       /*src=*/ null,
       /*id=*/ null,
       /*name=*/ null,
       /*reasons=*/['websocket'],
       /*children=*/[{
-        'preventedBackForwardCache': "no",
+        'blocked': false,
         'url': null,
         'src': rc1_child_url,
         // Id and name should be empty.
         'id': '',
         'name': '',
-        'reasons': null,
-        'children': null
+        'reasons': [],
+        'children': []
       }]);
 });
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js
index a9f12001..9f6b4e2 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.tentative.window.js
@@ -26,7 +26,7 @@
   await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false);
   await assertNotRestoredReasonsEquals(
       rc1,
-      /*preventedBackForwardCache=*/ "yes",
+      /*blocked=*/ true,
       /*url=*/ rc1_url,
       /*src=*/ null,
       /*id=*/ null,
@@ -39,7 +39,7 @@
   await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true);
   await assertNotRestoredReasonsEquals(
       rc1,
-      /*preventedBackForwardCache=*/ "yes",
+      /*blocked=*/ true,
       /*url=*/ rc1_url,
       /*src=*/ null,
       /*id=*/ null,
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js
index 851dd8c6..80adec0 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.tentative.window.js
@@ -44,20 +44,20 @@
   await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false);
   await assertNotRestoredReasonsEquals(
       rc1,
-      /*preventedBackForwardCache=*/ "no",
+      /*blocked=*/ false,
       /*url=*/ rc1_url,
       /*src=*/ null,
       /*id=*/ null,
       /*name=*/ null,
       /*reasons=*/[],
       /*children=*/[{
-        'preventedBackForwardCache': "yes",
+        'blocked': true,
         'url': null,
         'src': rc1_child_url,
         'id': 'test-id',
         // Iframes that are generated by addIframe have an empty name.
         'name': '',
-        'reasons': null,
-        'children': null
+        'reasons': [],
+        'children': []
       }]);
 });
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js
index 969af3d..db93dd9 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.tentative.window.js
@@ -27,7 +27,7 @@
   await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false);
   await assertNotRestoredReasonsEquals(
       rc1,
-      /*preventedBackForwardCache=*/ "yes",
+      /*blocked=*/ true,
       /*url=*/ rc1_url,
       /*src=*/ null,
       /*id=*/ null,
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js
index 1cbbad9..8f5a678f 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-reload.tentative.window.js
@@ -27,7 +27,7 @@
   await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false);
   await assertNotRestoredReasonsEquals(
       rc1,
-      /*preventedBackForwardCache=*/ "yes",
+      /*blocked=*/ true,
       /*url=*/ rc1_url,
       /*src=*/ null,
       /*id=*/ null,
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js
index 44b44a8..7339324 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-bfcache.tentative.window.js
@@ -38,21 +38,21 @@
   await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false);
   await assertNotRestoredReasonsEquals(
       rc1,
-      /*preventedBackForwardCache=*/ "no",
+      /*blocked=*/ false,
       /*url=*/ rc1_url,
       /*src=*/ null,
       /*id=*/ null,
       /*name=*/ null,
       /*reasons=*/[],
       /*children=*/[{
-        'preventedBackForwardCache': "yes",
+        'blocked': true,
         'url': rc1_child_url,
         'src': rc1_child_url,
         'id': 'test-id',
         'name': '',
         'reasons': ['websocket'],
         'children': [{
-          'preventedBackForwardCache': "no",
+          'blocked': false,
           'url': rc1_grand_child_url,
           'src': rc1_grand_child_url,
           'id': '',
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js
index 0e86bd0..a9f3a4e 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-same-origin-replace.tentative.window.js
@@ -31,10 +31,13 @@
   // Go back.
   await newRemoteContextHelper.historyBack();
 
+  const navigation_entry = await rc1.executeScript(() => {
+    return performance.getEntriesByType('navigation')[0];
+  });
   // Reasons are not reset for same-origin replace.
   await assertNotRestoredReasonsEquals(
       rc1,
-      /*preventedBackForwardCache=*/ "yes",
+      /*blocked=*/ true,
       /*url=*/ rc1_url,
       /*src=*/ null,
       /*id=*/ null,
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/test-helper.js b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/test-helper.js
index 20729c98..0737f71 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/test-helper.js
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/not-restored-reasons/test-helper.js
@@ -9,35 +9,27 @@
 
 function assertReasonsStructEquals(
     result, blocked, url, src, id, name, reasons, children) {
-  assert_equals(result.preventedBackForwardCache, blocked);
+  assert_equals(result.blocked, blocked);
   assert_equals(result.url, url);
   assert_equals(result.src, src);
   assert_equals(result.id, id);
   assert_equals(result.name, name);
   // Reasons should match.
-  if (reasons === null) {
-    assert_equals(result.reasons, reasons);
-  } else {
-    assert_equals(result.reasons.length, reasons.length);
-    reasons.sort();
-    result.reasons.sort();
-    for (let i = 0; i < reasons.length; i++) {
-      assert_equals(result.reasons[i], reasons[i]);
-    }
+  assert_equals(result.reasons.length, reasons.length);
+  reasons.sort();
+  result.reasons.sort();
+  for (let i = 0; i < reasons.length; i++) {
+    assert_equals(result.reasons[i], reasons[i]);
   }
-
   // Children should match.
-  if (children === null) {
-    assert_equals(result.children, children);
-  } else {
-    children.sort();
-    result.children.sort();
-    for (let j = 0; j < children.length; j++) {
-      assertReasonsStructEquals(
-          result.children[0], children[0].preventedBackForwardCache, children[0].url,
-          children[0].src, children[0].id, children[0].name, children[0].reasons,
-          children[0].children);
-    }
+  assert_equals(result.children.length, children.length);
+  children.sort();
+  result.children.sort();
+  for (let j = 0; j < children.length; j++) {
+    assertReasonsStructEquals(
+        result.children[0], children[0].blocked, children[0].url,
+        children[0].src, children[0].id, children[0].name, children[0].reasons,
+        children[0].children);
   }
 }
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/ignore-listed-sourcemap-detach.js b/third_party/blink/web_tests/http/tests/devtools/bindings/ignore-listed-sourcemap-detach.js
index f00dc4e..0356451c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/ignore-listed-sourcemap-detach.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/ignore-listed-sourcemap-detach.js
@@ -6,6 +6,7 @@
 import {ConsoleTestRunner} from 'console_test_runner';
 
 import * as SDK from 'devtools/core/sdk/sdk.js';
+import * as Common from 'devtools/core/common/common.js';
 
 (async function() {
   await TestRunner.loadLegacyModule('console');
@@ -16,7 +17,7 @@
 
   TestRunner.addSniffer(Bindings.IgnoreListManager.prototype, 'patternChangeFinishedForTests', step1);
   var frameworkRegexString = '.*';
-  Common.settingForTest('skipStackFramesPattern').set('.*');
+  Common.Settings.settingForTest('skipStackFramesPattern').set('.*');
 
   async function step1() {
     TestRunner.addResult('Evaluating script with source map');
diff --git a/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging-async.js b/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging-async.js
index dca004c..fdbd0d28 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging-async.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging-async.js
@@ -6,6 +6,8 @@
 import {ConsoleTestRunner} from 'console_test_runner';
 import {NetworkTestRunner} from 'network_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(
       `Tests that XMLHttpRequest Logging works when Enabled and doesn't show logs when Disabled for asynchronous XHRs.\n`);
@@ -18,7 +20,7 @@
   }
 
   function step1() {
-    Common.settingForTest('monitoringXHREnabled').set(true);
+    Common.Settings.settingForTest('monitoringXHREnabled').set(true);
     makeRequest(() => {
       TestRunner.deprecatedRunAfterPendingDispatches(async () => {
         TestRunner.addResult('XHR with logging enabled: ');
@@ -32,7 +34,7 @@
   }
 
   function step2() {
-    Common.settingForTest('monitoringXHREnabled').set(false);
+    Common.Settings.settingForTest('monitoringXHREnabled').set(false);
     makeRequest(() => {
       TestRunner.deprecatedRunAfterPendingDispatches(async () => {
         TestRunner.addResult('XHR with logging disabled: ');
diff --git a/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging-expected.txt
index 4a106b5..3194fb04 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging-expected.txt
@@ -5,83 +5,83 @@
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
-(anonymous) @ console-xhr-logging.js:23
-console-xhr-logging.js:16 sending a GET request to resources/xhr-exists.html
+requestHelper @ console-xhr-logging.js:19
+(anonymous) @ console-xhr-logging.js:25
+console-xhr-logging.js:18 sending a GET request to resources/xhr-exists.html
 
 Message count: 3
 VM:37 GET http://127.0.0.1:8000/devtools/resources/xhr-does-not-exist.html 404 (Not Found)
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
-(anonymous) @ console-xhr-logging.js:29
+requestHelper @ console-xhr-logging.js:19
+(anonymous) @ console-xhr-logging.js:31
 VM:37 XHR failed loading: GET "http://127.0.0.1:8000/devtools/resources/xhr-does-not-exist.html".
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
-(anonymous) @ console-xhr-logging.js:29
-console-xhr-logging.js:16 sending a GET request to resources/xhr-does-not-exist.html
+requestHelper @ console-xhr-logging.js:19
+(anonymous) @ console-xhr-logging.js:31
+console-xhr-logging.js:18 sending a GET request to resources/xhr-does-not-exist.html
 
 Message count: 2
 VM:37 XHR finished loading: POST "http://127.0.0.1:8000/devtools/resources/post-target.cgi".
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
+requestHelper @ console-xhr-logging.js:19
 (anonymous) @ VM:1
-console-xhr-logging.js:16 sending a POST request to resources/post-target.cgi
+console-xhr-logging.js:18 sending a POST request to resources/post-target.cgi
 
 Message count: 4
 VM:37 Access to XMLHttpRequest at 'http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
+requestHelper @ console-xhr-logging.js:19
 (anonymous) @ VM:1
 VM:37 GET http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html net::ERR_FAILED 200 (OK)
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
+requestHelper @ console-xhr-logging.js:19
 (anonymous) @ VM:1
 VM:37 XHR failed loading: GET "http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html".
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
+requestHelper @ console-xhr-logging.js:19
 (anonymous) @ VM:1
-console-xhr-logging.js:16 sending a GET request to http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html
+console-xhr-logging.js:18 sending a GET request to http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html
 
 Message count: 1
-console-xhr-logging.js:16 sending a GET request to resources/xhr-exists.html
+console-xhr-logging.js:18 sending a GET request to resources/xhr-exists.html
 
 Message count: 2
 VM:37 GET http://127.0.0.1:8000/devtools/resources/xhr-does-not-exist.html 404 (Not Found)
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
+requestHelper @ console-xhr-logging.js:19
 (anonymous) @ VM:1
-console-xhr-logging.js:16 sending a GET request to resources/xhr-does-not-exist.html
+console-xhr-logging.js:18 sending a GET request to resources/xhr-does-not-exist.html
 
 Message count: 1
-console-xhr-logging.js:16 sending a POST request to resources/post-target.cgi
+console-xhr-logging.js:18 sending a POST request to resources/post-target.cgi
 
 Message count: 3
 VM:37 Access to XMLHttpRequest at 'http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
+requestHelper @ console-xhr-logging.js:19
 (anonymous) @ VM:1
 VM:37 GET http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html net::ERR_FAILED 200 (OK)
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
-requestHelper @ console-xhr-logging.js:17
+requestHelper @ console-xhr-logging.js:19
 (anonymous) @ VM:1
-console-xhr-logging.js:16 sending a GET request to http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html
+console-xhr-logging.js:18 sending a GET request to http://localhost:8000/devtools/resources/cors-disabled/xhr-exists.html
 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging.js b/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging.js
index 2df12ed..ae0604e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console-xhr-logging.js
@@ -6,6 +6,8 @@
 import {ConsoleTestRunner} from 'console_test_runner';
 import {NetworkTestRunner} from 'network_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests that XMLHttpRequest Logging works when Enabled and doesn't show logs when Disabled.\n`);
   await TestRunner.loadLegacyModule('console');
@@ -17,8 +19,8 @@
           makeSimpleXHR(method, url, false);
       }
   `);
-  Common.settingForTest('consoleGroupSimilar').set(false);
-  Common.settingForTest('monitoringXHREnabled').set(true);
+  Common.Settings.settingForTest('consoleGroupSimilar').set(false);
+  Common.Settings.settingForTest('monitoringXHREnabled').set(true);
 
   TestRunner.evaluateInPage(`requestHelper('GET', 'resources/xhr-exists.html')`);
   await ConsoleTestRunner.waitForConsoleMessagesPromise(2);
@@ -44,7 +46,7 @@
   SDK.ConsoleModel.requestClearMessages();
   TestRunner.addResult('');
 
-  Common.settingForTest('monitoringXHREnabled').set(false);
+  Common.Settings.settingForTest('monitoringXHREnabled').set(false);
 
   TestRunner.evaluateInPageAsync(`requestHelper('GET', 'resources/xhr-exists.html')`);
   await ConsoleTestRunner.waitForConsoleMessagesPromise(1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location-expected.txt
index 942f846..e19e4a3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location-expected.txt
@@ -1,7 +1,7 @@
 Test that console.log() would linkify its location in respect with ignore-listing.
 
-foo.js:16 
-boo.js:23 
-console-linkify-message-location.js:28 
-foo.js:16 
+foo.js:18 
+boo.js:25 
+console-linkify-message-location.js:30 
+foo.js:18 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location.js b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location.js
index d1927b9b..e39ec534 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-linkify-message-location.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ConsoleTestRunner} from 'console_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Test that console.log() would linkify its location in respect with ignore-listing.\n`);
 
@@ -32,21 +34,21 @@
 
     TestRunner.addSniffer(Bindings.IgnoreListManager.prototype, 'patternChangeFinishedForTests', step2);
     var frameworkRegexString = 'foo\\.js';
-    Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+    Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
   }
 
   async function step2() {
     await dumpConsoleMessageURLs();
     TestRunner.addSniffer(Bindings.IgnoreListManager.prototype, 'patternChangeFinishedForTests', step3);
     var frameworkRegexString = 'foo\\.js|boo\\.js';
-    Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+    Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
   }
 
   async function step3() {
     await dumpConsoleMessageURLs();
     TestRunner.addSniffer(Bindings.IgnoreListManager.prototype, 'patternChangeFinishedForTests', step4);
     var frameworkRegexString = '';
-    Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+    Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
   }
 
   async function step4() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt
index 0063236..5e5201d1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework-expected.txt
@@ -1,5 +1,5 @@
 Tests console.log() anchor location when the skip-stack-frames feature is enabled.
 
-console-log-wrapped-in-framework.js:16 direct console.log()
-console-log-wrapped-in-framework.js:17 framework log
+console-log-wrapped-in-framework.js:18 direct console.log()
+console-log-wrapped-in-framework.js:19 framework log
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework.js b/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework.js
index 2cabc2b..30b10d19 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-log-wrapped-in-framework.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ConsoleTestRunner} from 'console_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests console.log() anchor location when the skip-stack-frames feature is enabled.\n`);
   await TestRunner.loadLegacyModule('console');
@@ -19,7 +21,7 @@
   `);
 
   var frameworkRegexString = '/framework\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   TestRunner.evaluateInPage('runLogs()');
   TestRunner.deprecatedRunAfterPendingDispatches(callback);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
index 42fbb4c0..d0acb4f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
@@ -5,12 +5,14 @@
 import {TestRunner} from 'test_runner';
 import {ConsoleTestRunner} from 'console_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests that the console can preserve log messages across cross-process navigations.`);
   await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
   await TestRunner.navigatePromise('http://devtools.oopif.test:8000/devtools/console/resources/log-message.html')
-  Common.settingForTest('preserveConsoleLog').set(true);
+  Common.Settings.settingForTest('preserveConsoleLog').set(true);
   await TestRunner.evaluateInPage(`logMessage('before navigation')`);
   await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/console/resources/log-message.html')
   await TestRunner.evaluateInPage(`logMessage('after navigation')`);
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log.js b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log.js
index b8f742e..fe5f3b17 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log.js
@@ -6,6 +6,7 @@
 import {ConsoleTestRunner} from 'console_test_runner';
 
 import * as SDK from 'devtools/core/sdk/sdk.js';
+import * as Common from 'devtools/core/common/common.js';
 
 (async function() {
   TestRunner.addResult(`Tests that the console can preserve log messages across navigations. Bug 53359\n`);
@@ -16,10 +17,10 @@
   consoleModel.addMessage(new SDK.ConsoleModel.ConsoleMessage(
       TestRunner.runtimeModel, Protocol.Log.LogEntrySource.Other,
       Protocol.Log.LogEntryLevel.Info, 'PASS'));
-  Common.settingForTest('preserveConsoleLog').set(true);
+  Common.Settings.settingForTest('preserveConsoleLog').set(true);
   TestRunner.reloadPage(async function() {
     await ConsoleTestRunner.dumpConsoleMessages();
-    Common.settingForTest('preserveConsoleLog').set(false);
+    Common.Settings.settingForTest('preserveConsoleLog').set(false);
     TestRunner.completeTest();
   });
 })();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp.js b/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp.js
index d161466..095c32f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-timestamp.js
@@ -6,6 +6,7 @@
 import {ConsoleTestRunner} from 'console_test_runner';
 
 import * as SDK from 'devtools/core/sdk/sdk.js';
+import * as Common from 'devtools/core/common/common.js';
 
 (async function() {
   TestRunner.addResult(`Tests the console timestamp setting.\n`);
@@ -18,7 +19,7 @@
   var tzOffset = new Date(baseDate).getTimezoneOffset() * 60 * 1000;
   var baseTimestamp = 1400000000000 + tzOffset;
 
-  Common.settingForTest('consoleGroupSimilar').set(false);
+  Common.Settings.settingForTest('consoleGroupSimilar').set(false);
 
   function addMessageWithFixedTimestamp(messageText, timestamp, type) {
     var message = new SDK.ConsoleModel.ConsoleMessage(
@@ -54,14 +55,14 @@
   await ConsoleTestRunner.dumpConsoleMessages();
 
   TestRunner.addResult('Console messages with timestamps enabled:');
-  Common.settingForTest('consoleTimestampsEnabled').set(true);
+  Common.Settings.settingForTest('consoleTimestampsEnabled').set(true);
 
   addMessageWithFixedTimestamp('<After>', baseTimestamp + 1000);
   addMessageWithFixedTimestamp('<After>', baseTimestamp + 1000);
   addMessageWithFixedTimestamp('<After>', baseTimestamp + 1456);
 
-  Common.settingForTest('consoleTimestampsEnabled').set(false);
-  Common.settingForTest('consoleTimestampsEnabled').set(true);
+  Common.Settings.settingForTest('consoleTimestampsEnabled').set(false);
+  Common.Settings.settingForTest('consoleTimestampsEnabled').set(true);
 
   await ConsoleTestRunner.dumpConsoleMessages();
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/shadow-element.js b/third_party/blink/web_tests/http/tests/devtools/console/shadow-element.js
index 6fedb3c..377ad2d8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/shadow-element.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/shadow-element.js
@@ -6,6 +6,8 @@
 import {ConsoleTestRunner} from 'console_test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests that $0 works with shadow dom.\n`);
   await TestRunner.loadLegacyModule('console');
@@ -20,7 +22,7 @@
         sr.innerHTML = "<div><div><div id='shadow'><input id='user-agent-host' type='range'></div></div></div>";
     `);
 
-  Common.settingForTest('showUAShadowDOM').set(true);
+  Common.Settings.settingForTest('showUAShadowDOM').set(true);
   ElementsTestRunner.selectNodeWithId('shadow', step1);
 
   function step1() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/elements-hide-html-comments.js b/third_party/blink/web_tests/http/tests/devtools/elements/elements-hide-html-comments.js
index d251ca35..10cf409 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/elements-hide-html-comments.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/elements-hide-html-comments.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Verifies show/hide HTML comments setting.\n`);
   await TestRunner.loadLegacyModule('elements');
@@ -36,7 +38,7 @@
   function onNodeSelected() {
     TestRunner.addResult('HTML comments shown:');
     ElementsTestRunner.dumpElementsTree();
-    Common.settingForTest('showHTMLComments').set(false);
+    Common.Settings.settingForTest('showHTMLComments').set(false);
     TestRunner.addResult('\nHTML comments hidden:');
     ElementsTestRunner.dumpElementsTree();
     TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-custom-framework-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-custom-framework-expected.txt
index 9d429d2..c52db350 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-custom-framework-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-custom-framework-expected.txt
@@ -4,7 +4,7 @@
 
 ======== click ========
 == Framework
-[expanded] button#inspectedNodeRemoveevent-listener-sidebar-custom-framework.js:34
+[expanded] button#inspectedNodeRemoveevent-listener-sidebar-custom-framework.js:36
     useCapture: false
     passive: false
     once: false
@@ -19,7 +19,7 @@
 
 ======== customFirst ========
 == FrameworkUser
-[expanded] button#inspectedNodeevent-listener-sidebar-custom-framework.js:24
+[expanded] button#inspectedNodeevent-listener-sidebar-custom-framework.js:26
     useCapture: true
     passive: false
     once: false
@@ -30,7 +30,7 @@
 
 ======== customSecond ========
 == FrameworkUser
-[expanded] button#inspectedNodeevent-listener-sidebar-custom-framework.js:29
+[expanded] button#inspectedNodeevent-listener-sidebar-custom-framework.js:31
     useCapture: false
     passive: false
     once: false
@@ -42,7 +42,7 @@
 
 ======== click ========
 == Raw
-[expanded] button#inspectedNodeRemoveevent-listener-sidebar-custom-framework.js:34
+[expanded] button#inspectedNodeRemoveevent-listener-sidebar-custom-framework.js:36
     useCapture: false
     passive: false
     once: false
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-custom-framework.js b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-custom-framework.js
index 8873b44..58a0476 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-custom-framework.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-custom-framework.js
@@ -6,6 +6,8 @@
 import {ElementsTestRunner} from 'elements_test_runner';
 import {ConsoleTestRunner} from 'console_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests framework event listeners output in the Elements sidebar panel.\n`);
   await TestRunner.loadLegacyModule('elements');
@@ -105,7 +107,7 @@
       setupNormalPath();
   `);
 
-  Common.settingForTest('showEventListenersForAncestors').set(false);
+  Common.Settings.settingForTest('showEventListenersForAncestors').set(false);
   ElementsTestRunner.selectNodeWithId('inspectedNode', step1);
 
   function step1() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-expected.txt
index e82128f..17a3e144 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-expected.txt
@@ -3,43 +3,43 @@
 
 ======== click ========
 == Raw
-[expanded] documentRemoveevent-listener-sidebar.js:18
+[expanded] documentRemoveevent-listener-sidebar.js:20
     useCapture: false
     passive: false
     once: false
     handler: function documentClickHandler(event) { console.log("click - document - attribute"); }
 == Raw
-[expanded] documentRemoveevent-listener-sidebar.js:43
+[expanded] documentRemoveevent-listener-sidebar.js:45
     useCapture: true
     passive: false
     once: false
     handler: function() { console.log("click - document - handleEvent"); }
 == Raw
-[expanded] documentRemoveevent-listener-sidebar.js:31
+[expanded] documentRemoveevent-listener-sidebar.js:33
     useCapture: true
     passive: false
     once: false
     handler: function(event) { console.log("click - document - capturing"); }
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar.js:29
+[expanded] button#nodeRemoveevent-listener-sidebar.js:31
     useCapture: false
     passive: false
     once: false
     handler: function(event) { console.log("click - button - bubbling (registered after attribute)"); }
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar.js:28
+[expanded] button#nodeRemoveevent-listener-sidebar.js:30
     useCapture: false
     passive: false
     once: false
     handler: function(event) { console.log("click - button - attribute"); }
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar.js:24
+[expanded] button#nodeRemoveevent-listener-sidebar.js:26
     useCapture: false
     passive: false
     once: false
     handler: function clickHandler(event) { console.log("click - button - bubbling (registered before attribute)"); }
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar.js:27
+[expanded] button#nodeRemoveevent-listener-sidebar.js:29
     useCapture: true
     passive: false
     once: false
@@ -47,7 +47,7 @@
 
 ======== custom event ========
 == Raw
-[expanded] bodyRemoveevent-listener-sidebar.js:22
+[expanded] bodyRemoveevent-listener-sidebar.js:24
     useCapture: true
     passive: false
     once: true
@@ -55,7 +55,7 @@
 
 ======== hover ========
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar.js:26
+[expanded] button#nodeRemoveevent-listener-sidebar.js:28
     useCapture: false
     passive: false
     once: false
@@ -63,7 +63,7 @@
 
 ======== wheel ========
 == Raw
-[expanded] bodyRemoveToggle Passiveevent-listener-sidebar.js:22
+[expanded] bodyRemoveToggle Passiveevent-listener-sidebar.js:24
     useCapture: false
     passive: true
     once: false
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery1-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery1-expected.txt
index 7574b0d..bc51f47 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery1-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery1-expected.txt
@@ -3,19 +3,19 @@
 
 ======== click ========
 == FrameworkUser
-[expanded] button#nodeRemoveevent-listener-sidebar-jquery1.js:21
+[expanded] button#nodeRemoveevent-listener-sidebar-jquery1.js:23
     useCapture: true
     passive: false
     once: false
     handler: function(){ console.log("second jquery"); }
 == FrameworkUser
-[expanded] button#nodeRemoveevent-listener-sidebar-jquery1.js:20
+[expanded] button#nodeRemoveevent-listener-sidebar-jquery1.js:22
     useCapture: true
     passive: false
     once: false
     handler: function(){ console.log("first jquery"); }
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar-jquery1.js:22
+[expanded] button#nodeRemoveevent-listener-sidebar-jquery1.js:24
     useCapture: false
     passive: false
     once: false
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery1.js b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery1.js
index 5625d28..001bb13 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery1.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery1.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests event listeners output in the Elements sidebar panel.\n`);
   await TestRunner.loadLegacyModule('elements');
@@ -25,7 +27,7 @@
       setupEventListeners();
   `);
 
-  Common.settingForTest('showEventListenersForAncestors').set(true);
+  Common.Settings.settingForTest('showEventListenersForAncestors').set(true);
   ElementsTestRunner.selectNodeWithId('node', step1);
 
   function step1() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery2-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery2-expected.txt
index fb8f9e4..1a72963 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery2-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery2-expected.txt
@@ -3,25 +3,25 @@
 
 ======== click ========
 == FrameworkUser
-[expanded] button#nodeRemoveevent-listener-sidebar-jquery2.js:21
+[expanded] button#nodeRemoveevent-listener-sidebar-jquery2.js:23
     useCapture: true
     passive: false
     once: false
     handler: function(){ console.log("second jquery"); }
 == FrameworkUser
-[expanded] button#nodeRemoveevent-listener-sidebar-jquery2.js:20
+[expanded] button#nodeRemoveevent-listener-sidebar-jquery2.js:22
     useCapture: true
     passive: false
     once: false
     handler: function(){ console.log("first jquery"); }
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar-jquery2.js:23
+[expanded] button#nodeRemoveevent-listener-sidebar-jquery2.js:25
     useCapture: false
     passive: false
     once: false
     handler: function() { console.log("onclick"); }
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar-jquery2.js:22
+[expanded] button#nodeRemoveevent-listener-sidebar-jquery2.js:24
     useCapture: false
     passive: false
     once: false
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery2.js b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery2.js
index bb366cd0..76d4b0d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery2.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-jquery2.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests event listeners output in the Elements sidebar panel.\n`);
   await TestRunner.loadLegacyModule('elements');
@@ -26,7 +28,7 @@
       setupEventListeners();
   `);
 
-  Common.settingForTest('showEventListenersForAncestors').set(true);
+  Common.Settings.settingForTest('showEventListenersForAncestors').set(true);
   ElementsTestRunner.selectNodeWithId('node', step1);
 
   function step1() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-remove-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-remove-expected.txt
index 2b6e21a..c1a2531 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-remove-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-remove-expected.txt
@@ -3,7 +3,7 @@
 
 ======== click ========
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar-remove.js:19
+[expanded] button#nodeRemoveevent-listener-sidebar-remove.js:21
     useCapture: false
     passive: false
     once: false
@@ -11,7 +11,7 @@
 
 ======== mouseover ========
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar-remove.js:19
+[expanded] button#nodeRemoveevent-listener-sidebar-remove.js:21
     useCapture: false
     passive: false
     once: false
@@ -20,7 +20,7 @@
 
 ======== mouseover ========
 == Raw
-[expanded] button#nodeRemoveevent-listener-sidebar-remove.js:19
+[expanded] button#nodeRemoveevent-listener-sidebar-remove.js:21
     useCapture: false
     passive: false
     once: false
@@ -29,7 +29,7 @@
 
 ======== click ========
 == Raw
-[expanded] button#node-siblingRemoveevent-listener-sidebar-remove.js:20
+[expanded] button#node-siblingRemoveevent-listener-sidebar-remove.js:22
     useCapture: false
     passive: false
     once: false
@@ -37,7 +37,7 @@
 
 ======== mouseover ========
 == Raw
-[expanded] button#node-siblingRemoveevent-listener-sidebar-remove.js:20
+[expanded] button#node-siblingRemoveevent-listener-sidebar-remove.js:22
     useCapture: false
     passive: false
     once: false
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-remove.js b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-remove.js
index 742a19f..efbbf83 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-remove.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar-remove.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests removing event listeners in the Elements sidebar panel.\n`);
   await TestRunner.loadLegacyModule('elements');
@@ -29,7 +31,7 @@
       setupEventListeners();
   `);
 
-  Common.settingForTest('showEventListenersForAncestors').set(false);
+  Common.Settings.settingForTest('showEventListenersForAncestors').set(false);
 
 
   function step1() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar.js b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar.js
index dc2166e..0c5ef57e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listener-sidebar.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests event listeners output in the Elements sidebar panel.\n`);
   await TestRunner.loadLegacyModule('elements');
@@ -50,7 +52,7 @@
       setupEventListeners();
   `);
 
-  Common.settingForTest('showEventListenersForAncestors').set(true);
+  Common.Settings.settingForTest('showEventListenersForAncestors').set(true);
   ElementsTestRunner.selectNodeWithId('node', step1);
 
   function step1() {
@@ -62,7 +64,7 @@
   }
 
   function step3() {
-    Common.settingForTest('showEventListenersForAncestors').set(false);
+    Common.Settings.settingForTest('showEventListenersForAncestors').set(false);
     TestRunner.addResult('Listeners for selected node only(should be no listeners):');
     ElementsTestRunner.expandAndDumpSelectedElementEventListeners(step4);
   }
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-about-blank-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-about-blank-expected.txt
index c8dc3c2..8153f520 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-about-blank-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-about-blank-expected.txt
@@ -3,7 +3,7 @@
 
 ======== click ========
 == Raw
-[expanded] bodyRemoveevent-listeners-about-blank.js:19
+[expanded] bodyRemoveevent-listeners-about-blank.js:21
     useCapture: true
     passive: false
     once: false
@@ -11,7 +11,7 @@
 
 ======== hover ========
 == Raw
-[expanded] div#div-in-iframeRemoveevent-listeners-about-blank.js:19
+[expanded] div#div-in-iframeRemoveevent-listeners-about-blank.js:21
     useCapture: true
     passive: false
     once: true
@@ -19,7 +19,7 @@
 
 ======== wheel ========
 == Raw
-[expanded] bodyRemoveToggle Passiveevent-listeners-about-blank.js:19
+[expanded] bodyRemoveToggle Passiveevent-listeners-about-blank.js:21
     useCapture: false
     passive: true
     once: false
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-about-blank.js b/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-about-blank.js
index 55a0fe9e..57feb90 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-about-blank.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-about-blank.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(
       `Tests event listeners output in the Elements sidebar panel when the listeners are added on an element in about:blank page.\n`);
@@ -28,7 +30,7 @@
       }
   `);
 
-  Common.settingForTest('showEventListenersForAncestors').set(true);
+  Common.Settings.settingForTest('showEventListenersForAncestors').set(true);
   TestRunner.evaluateInPage('setupEventListeners()', step1);
 
   function step1() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-framework-with-service-worker.js b/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-framework-with-service-worker.js
index 66cf16f..2c91d02 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-framework-with-service-worker.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/event-listeners-framework-with-service-worker.js
@@ -9,6 +9,7 @@
 import {ApplicationTestRunner} from 'application_test_runner';
 
 import * as SDK from 'devtools/core/sdk/sdk.js';
+import * as Common from 'devtools/core/common/common.js';
 
 (async function() {
   TestRunner.addResult(`Tests framework event listeners output in Sources panel when service worker is present.\n`);
@@ -28,7 +29,7 @@
       </body>
     `);
 
-  Common.settingForTest('showEventListenersForAncestors').set(false);
+  Common.Settings.settingForTest('showEventListenersForAncestors').set(false);
   var scriptURL = 'http://127.0.0.1:8000/devtools/service-workers/resources/service-worker-empty.js';
   var scope = 'http://127.0.0.1:8000/devtools/service-workers/resources/scope1/';
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-1.js b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-1.js
index 77a5f1c..0680b91 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-1.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-1.js
@@ -6,6 +6,7 @@
 import {ElementsTestRunner} from 'elements_test_runner';
 
 import * as SDK from 'devtools/core/sdk/sdk.js';
+import * as Common from 'devtools/core/common/common.js';
 
 (async function() {
   TestRunner.addResult(`Tests that elements panel preserves selected shadow DOM node on page refresh.\n`);
@@ -15,7 +16,7 @@
 
   TestRunner.runTestSuite([
     function setup(next) {
-      Common.settingForTest('showUAShadowDOM').set(true);
+      Common.Settings.settingForTest('showUAShadowDOM').set(true);
       ElementsTestRunner.expandElementsTree(next);
     },
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-2.js b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-2.js
index 83408f1..92540bb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-2.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-2.js
@@ -6,6 +6,7 @@
 import {ElementsTestRunner} from 'elements_test_runner';
 
 import * as SDK from 'devtools/core/sdk/sdk.js';
+import * as Common from 'devtools/core/common/common.js';
 
 (async function() {
   TestRunner.addResult(`Tests that elements panel preserves selected shadow DOM node on page refresh.\n`);
@@ -15,7 +16,7 @@
 
   TestRunner.runTestSuite([
     function setup(next) {
-      Common.settingForTest('showUAShadowDOM').set(true);
+      Common.Settings.settingForTest('showUAShadowDOM').set(true);
       ElementsTestRunner.expandElementsTree(next);
     },
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-3.js b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-3.js
index bc245b6..ded1f11 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-3.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-3.js
@@ -6,6 +6,7 @@
 import {ElementsTestRunner} from 'elements_test_runner';
 
 import * as SDK from 'devtools/core/sdk/sdk.js';
+import * as Common from 'devtools/core/common/common.js';
 
 (async function() {
   TestRunner.addResult(`Tests that elements panel preserves selected shadow DOM node on page refresh.\n`);
@@ -16,7 +17,7 @@
 
   TestRunner.runTestSuite([
     function setup(next) {
-      Common.settingForTest('showUAShadowDOM').set(true);
+      Common.Settings.settingForTest('showUAShadowDOM').set(true);
       ElementsTestRunner.expandElementsTree(next);
     },
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/reveal-shadow-dom-node.js b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/reveal-shadow-dom-node.js
index 19ae0b8..2f9f15c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/reveal-shadow-dom-node.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/reveal-shadow-dom-node.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(
       `This test verifies that the correct node is revealed in the DOM tree when asked to reveal a user-agent shadow DOM node.\n`);
@@ -48,7 +50,7 @@
       var shadowDiv = children[0];
       TestRunner.addResult('User-agent shadow DOM hidden:');
       UI.panels.elements.revealAndSelectNode(shadowDiv).then(() => {
-        Common.settingForTest('showUAShadowDOM').set(true);
+        Common.Settings.settingForTest('showUAShadowDOM').set(true);
         TestRunner.addResult('User-agent shadow DOM shown:');
         UI.panels.elements.revealAndSelectNode(shadowDiv);
       });
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated.js b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated.js
index 7d856edf..155997a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {ElementsTestRunner} from 'elements_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests that sourcemap is applied correctly when specified by the respective HTTP header.\n`);
   await TestRunner.loadLegacyModule('elements');
@@ -24,7 +26,7 @@
       }
   `);
 
-  Common.settingForTest('cssSourceMapsEnabled').set(true);
+  Common.Settings.settingForTest('cssSourceMapsEnabled').set(true);
   TestRunner.addSniffer(Bindings.CSSWorkspaceBinding.prototype, 'updateLocations', step1);
   TestRunner.evaluateInPage('addStylesheet()');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation-expected.txt b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation-expected.txt
index 89e0f4f..95f4f01f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation-expected.txt
@@ -1,4 +1,4 @@
 Tests that console preserves log on oopif navigation
-oopif-console-preser…me-navigation.js:15 Before navigation
-oopif-console-preser…me-navigation.js:17 After navigation
+oopif-console-preser…me-navigation.js:17 Before navigation
+oopif-console-preser…me-navigation.js:19 After navigation
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation.js b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation.js
index 645ad58..52ca510 100644
--- a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation.js
+++ b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-console-preserves-log-on-frame-navigation.js
@@ -5,12 +5,14 @@
 import {TestRunner} from 'test_runner';
 import {ConsoleTestRunner} from 'console_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests that console preserves log on oopif navigation`);
   await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('console');
 
-  Common.settingForTest('preserveConsoleLog').set(false);
+  Common.Settings.settingForTest('preserveConsoleLog').set(false);
   await TestRunner.navigatePromise('resources/empty.html');
   await TestRunner.evaluateInPage(`console.log('Before navigation')`);
   await TestRunner.addIframe('http://devtools.oopif.test:8000/devtools/oopif/resources/empty.html');
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-1-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-1-expected.txt
index 5ff89be..029df2b6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-1-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-1-expected.txt
@@ -4,7 +4,7 @@
 Running: testDOMBreakpoint
 Call stack:
   * 0) Framework.appendChild (framework.js:72)
-    1) appendElement (frameworks-dom-xhr-event-breakpoints-1.js:26)
+    1) appendElement (frameworks-dom-xhr-event-breakpoints-1.js:28)
     2)  (:1)
     [setTimeout]
     0)  (:1)
@@ -13,7 +13,7 @@
 Running: testXHRBreakpoint
 Call stack:
   * 0) Framework.sendXHR (framework.js:79)
-    1) sendXHR (frameworks-dom-xhr-event-breakpoints-1.js:31)
+    1) sendXHR (frameworks-dom-xhr-event-breakpoints-1.js:33)
     2)  (:1)
     [setTimeout]
     0)  (:1)
@@ -21,20 +21,20 @@
 
 Running: testEventListenerBreakpoint
 Call stack:
-    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-1.js:38)
+    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-1.js:40)
   * 1) Framework_bound (framework.js:105)
   * 2) Framework_eventListener (framework.js:86)
-    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-1.js:49)
+    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-1.js:51)
     4)  (:1)
     [setTimeout]
     0)  (:1)
 
 Executing Resume...
 Call stack:
-    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-1.js:38)
+    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-1.js:40)
   * 1) Framework_bound (framework.js:105)
   * 2) Framework_eventListener (framework.js:86)
-    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-1.js:55)
+    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-1.js:57)
     4)  (:1)
     [setTimeout]
     0)  (:1)
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-1.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-1.js
index 0d03b38ef..31783f2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-1.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-1.js
@@ -6,6 +6,8 @@
 import {ElementsTestRunner} from 'elements_test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(
       `Tests framework black-boxing on DOM, XHR and Event breakpoints.\n`);
@@ -84,7 +86,7 @@
   `);
 
   var frameworkRegexString = '/framework\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.setQuiet(true);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-2-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-2-expected.txt
index dfc453c..60a9faf 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-2-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-2-expected.txt
@@ -4,14 +4,14 @@
 Running: testSteppingThroughEventListenerBreakpoint
 Executing StepOver...
 Call stack:
-    0) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:45)
+    0) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:47)
     1)  (:1)
     [setTimeout]
     0)  (:1)
 
 Executing StepOver...
 Call stack:
-    0) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:46)
+    0) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:48)
     1)  (:1)
     [setTimeout]
     0)  (:1)
@@ -20,10 +20,10 @@
 Executing StepOver...
 Executing StepOver...
 Call stack:
-    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:38)
+    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:40)
   * 1) Framework_bound (framework.js:105)
   * 2) Framework_eventListener (framework.js:86)
-    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:49)
+    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:51)
     4)  (:1)
     [setTimeout]
     0)  (:1)
@@ -34,10 +34,10 @@
 Executing StepOver...
 Executing StepOver...
 Call stack:
-    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:38)
+    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:40)
   * 1) Framework_bound (framework.js:105)
   * 2) Framework_eventListener (framework.js:86)
-    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:55)
+    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:57)
     4)  (:1)
     [setTimeout]
     0)  (:1)
@@ -46,7 +46,7 @@
 Executing StepOver...
 Executing StepOver...
 Call stack:
-    0) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:57)
+    0) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:59)
     1)  (:1)
     [setTimeout]
     0)  (:1)
@@ -56,10 +56,10 @@
 Running: testSteppingOutOnEventListenerBreakpoint
 Executing StepOut...
 Call stack:
-    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:38)
+    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:40)
   * 1) Framework_bound (framework.js:105)
   * 2) Framework_eventListener (framework.js:86)
-    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:49)
+    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:51)
     4)  (:1)
     [setTimeout]
     0)  (:1)
@@ -67,17 +67,17 @@
 Executing StepOut...
 Executing StepOut...
 Call stack:
-    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:38)
+    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:40)
   * 1) Framework_bound (framework.js:105)
   * 2) Framework_eventListener (framework.js:86)
-    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:55)
+    3) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:57)
     4)  (:1)
     [setTimeout]
     0)  (:1)
 
 Executing StepOut...
 Call stack:
-    0) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:56)
+    0) addListenerAndClick (frameworks-dom-xhr-event-breakpoints-2.js:58)
     1)  (:1)
     [setTimeout]
     0)  (:1)
@@ -87,28 +87,28 @@
 Running: testSteppingOutOnEventListenerBreakpointAllBlackboxedButOne
 Executing StepOut...
 Call stack:
-    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:64)
+    0) testElementClicked (frameworks-dom-xhr-event-breakpoints-2.js:66)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:10)
   * 3) Framework_bound (framework.js:105)
   * 4) Framework_eventListener (framework.js:86)
-    5) inner (frameworks-dom-xhr-event-breakpoints-2.js:76)
-    6) addFewBlackboxedListenersAndClick (frameworks-dom-xhr-event-breakpoints-2.js:82)
+    5) inner (frameworks-dom-xhr-event-breakpoints-2.js:78)
+    6) addFewBlackboxedListenersAndClick (frameworks-dom-xhr-event-breakpoints-2.js:84)
     7)  (:1)
     [setTimeout]
     0)  (:1)
 
 Executing StepOut...
 Call stack:
-    0) inner (frameworks-dom-xhr-event-breakpoints-2.js:77)
-    1) addFewBlackboxedListenersAndClick (frameworks-dom-xhr-event-breakpoints-2.js:82)
+    0) inner (frameworks-dom-xhr-event-breakpoints-2.js:79)
+    1) addFewBlackboxedListenersAndClick (frameworks-dom-xhr-event-breakpoints-2.js:84)
     2)  (:1)
     [setTimeout]
     0)  (:1)
 
 Executing StepOut...
 Call stack:
-    0) addFewBlackboxedListenersAndClick (frameworks-dom-xhr-event-breakpoints-2.js:82)
+    0) addFewBlackboxedListenersAndClick (frameworks-dom-xhr-event-breakpoints-2.js:84)
     1)  (:1)
     [setTimeout]
     0)  (:1)
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-2.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-2.js
index 38b4df52..7c4569e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-2.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints-2.js
@@ -6,6 +6,8 @@
 import {ElementsTestRunner} from 'elements_test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(
       `Tests framework black-boxing on DOM, XHR and Event breakpoints.\n`);
@@ -84,7 +86,7 @@
   `);
 
   var frameworkRegexString = '/framework\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.setQuiet(true);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-ignore-list-by-source-code-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-ignore-list-by-source-code-expected.txt
index b2aab211..db75108 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-ignore-list-by-source-code-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-ignore-list-by-source-code-expected.txt
@@ -2,7 +2,7 @@
 
 Set timer for test function.
 Call stack:
-    0) testFunction (frameworks-ignore-list-by-source-code.js:15)
+    0) testFunction (frameworks-ignore-list-by-source-code.js:17)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
@@ -10,7 +10,7 @@
 Executing StepInto...
 Executing StepInto...
 Call stack:
-    0) testFunction (frameworks-ignore-list-by-source-code.js:17)
+    0) testFunction (frameworks-ignore-list-by-source-code.js:19)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-ignore-list-by-source-code.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-ignore-list-by-source-code.js
index a41e425..23746885 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-ignore-list-by-source-code.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-ignore-list-by-source-code.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests provisional ignore-listing.\n`);
   await TestRunner.loadLegacyModule('sources');
@@ -23,7 +25,7 @@
   function step1() {
     TestRunner.addSniffer(Bindings.IgnoreListManager.prototype, 'patternChangeFinishedForTests', step2);
     var frameworkRegexString = '^framework\\.js$';
-    Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+    Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
   }
 
   function step2() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery-expected.txt
index 6534759..449f9f7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery-expected.txt
@@ -2,7 +2,7 @@
 
 Set timer for test function.
 Call stack:
-    0) testFunction (frameworks-jquery.js:35)
+    0) testFunction (frameworks-jquery.js:37)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
@@ -10,24 +10,24 @@
 Executing StepInto...
 Executing StepInto...
 Call stack:
-    0) onEachScript (frameworks-jquery.js:53)
+    0) onEachScript (frameworks-jquery.js:55)
   * 1) each (jquery-1.11.1.min.js:2)
   * 2) each (jquery-1.11.1.min.js:2)
-    3) testFunction (frameworks-jquery.js:37)
+    3) testFunction (frameworks-jquery.js:39)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepOut...
 Call stack:
-    0) testFunction (frameworks-jquery.js:38)
+    0) testFunction (frameworks-jquery.js:40)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepInto...
 Call stack:
-    0) onTestEvent1 (frameworks-jquery.js:43)
+    0) onTestEvent1 (frameworks-jquery.js:45)
   * 1) dispatch (jquery-1.11.1.min.js:3)
   * 2) r.handle (jquery-1.11.1.min.js:3)
   * 3) trigger (jquery-1.11.1.min.js:3)
@@ -35,7 +35,7 @@
   * 5) each (jquery-1.11.1.min.js:2)
   * 6) each (jquery-1.11.1.min.js:2)
   * 7) trigger (jquery-1.11.1.min.js:3)
-    8) testFunction (frameworks-jquery.js:38)
+    8) testFunction (frameworks-jquery.js:40)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
@@ -43,7 +43,7 @@
 Executing StepOver...
 Executing StepOver...
 Call stack:
-    0) onTestEvent2 (frameworks-jquery.js:48)
+    0) onTestEvent2 (frameworks-jquery.js:50)
   * 1) dispatch (jquery-1.11.1.min.js:3)
   * 2) r.handle (jquery-1.11.1.min.js:3)
   * 3) trigger (jquery-1.11.1.min.js:3)
@@ -51,7 +51,7 @@
   * 5) each (jquery-1.11.1.min.js:2)
   * 6) each (jquery-1.11.1.min.js:2)
   * 7) trigger (jquery-1.11.1.min.js:3)
-    8) testFunction (frameworks-jquery.js:38)
+    8) testFunction (frameworks-jquery.js:40)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js
index edf1faa..48efca0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests framework blackboxing feature on jQuery.\n`);
 
@@ -55,7 +57,7 @@
   `);
 
   var frameworkRegexString = '/jquery-1\\.11\\.1\\.min\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
   SourcesTestRunner.startDebuggerTest(step1, true);
 
   function step1() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-break-program-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-break-program-expected.txt
index 2913017..cc5ceb42 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-break-program-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-break-program-expected.txt
@@ -2,5 +2,5 @@
 
 Set timer for test function.
 Call stack:
-    0) stop (frameworks-skip-break-program.js:32)
+    0) stop (frameworks-skip-break-program.js:34)
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-break-program.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-break-program.js
index 5c3824d..dd0ed33c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-break-program.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-break-program.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(
       `Tests that framework blackboxing skips instant pauses (e.g. breakpoints on console.assert(), setTimeout(), etc.) if they happen entirely inside the framework.\n`);
@@ -34,7 +36,7 @@
   `);
 
   var frameworkRegexString = '/framework\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.startDebuggerTest(step1, true);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-exceptions-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-exceptions-expected.txt
index b09195a..7631b32 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-exceptions-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-exceptions-expected.txt
@@ -2,5 +2,5 @@
 
 Set timer for test function.
 Call stack:
-    0) testFunction (frameworks-skip-exceptions.js:24)
+    0) testFunction (frameworks-skip-exceptions.js:26)
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-exceptions.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-exceptions.js
index 22afb4d..6c851d4 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-exceptions.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-exceptions.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(
       `Tests that framework black-boxing skips exceptions, including those that happened deeper inside V8 native script.\n`);
@@ -26,7 +28,7 @@
   `);
 
   var frameworkRegexString = '/framework\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.setQuiet(true);
   SourcesTestRunner.startDebuggerTest(step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in-expected.txt
index 89f37f31..a609d40 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in-expected.txt
@@ -2,40 +2,40 @@
 
 Set timer for test function.
 Call stack:
-    0) test1 (frameworks-skip-step-in.js:32)
-    1) testFunction (frameworks-skip-step-in.js:20)
+    0) test1 (frameworks-skip-step-in.js:34)
+    1) testFunction (frameworks-skip-step-in.js:22)
 
 Call stack:
-    0) test2 (frameworks-skip-step-in.js:38)
-    1) testFunction (frameworks-skip-step-in.js:20)
+    0) test2 (frameworks-skip-step-in.js:40)
+    1) testFunction (frameworks-skip-step-in.js:22)
 
 Call stack:
-    0) callback (frameworks-skip-step-in.js:25)
+    0) callback (frameworks-skip-step-in.js:27)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:10)
-    3) test3 (frameworks-skip-step-in.js:43)
-    4) testFunction (frameworks-skip-step-in.js:20)
+    3) test3 (frameworks-skip-step-in.js:45)
+    4) testFunction (frameworks-skip-step-in.js:22)
 
 Call stack:
-    0) callback (frameworks-skip-step-in.js:25)
+    0) callback (frameworks-skip-step-in.js:27)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:10)
-    3) test4 (frameworks-skip-step-in.js:49)
-    4) testFunction (frameworks-skip-step-in.js:20)
+    3) test4 (frameworks-skip-step-in.js:51)
+    4) testFunction (frameworks-skip-step-in.js:22)
 
 Call stack:
-    0) callback (frameworks-skip-step-in.js:25)
+    0) callback (frameworks-skip-step-in.js:27)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:13)
   * 3) Framework.safeRun (framework.js:10)
-    4) test5 (frameworks-skip-step-in.js:55)
-    5) testFunction (frameworks-skip-step-in.js:20)
+    4) test5 (frameworks-skip-step-in.js:57)
+    5) testFunction (frameworks-skip-step-in.js:22)
 
 Call stack:
-    0) callback (frameworks-skip-step-in.js:25)
+    0) callback (frameworks-skip-step-in.js:27)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:10)
-    3) test6 (frameworks-skip-step-in.js:61)
-    4) testFunction (frameworks-skip-step-in.js:20)
+    3) test6 (frameworks-skip-step-in.js:63)
+    4) testFunction (frameworks-skip-step-in.js:22)
 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in.js
index b81a6a5..d682f15 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-skip-step-in.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests the skip stack frames feature when stepping.\n`);
   await TestRunner.loadLegacyModule('sources');
@@ -65,7 +67,7 @@
   var frameworkRegexString = '/framework\\.js$';
   var totalDebuggerStatements = 6;
 
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.setQuiet(true);
   SourcesTestRunner.startDebuggerTest(step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-sourcemap.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-sourcemap.js
index 2b6b0c7a..84b70512 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-sourcemap.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-sourcemap.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests framework blackboxing feature with sourcemaps.\n`);
   await TestRunner.loadLegacyModule('sources');
@@ -25,7 +27,7 @@
 
   TestRunner.addSniffer(Bindings.BlackboxManager.prototype, '_patternChangeFinishedForTests', step1);
   var frameworkRegexString = '/framework\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   function step1() {
     SourcesTestRunner.startDebuggerTest(step2, true);
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
index 3166e90..5a26fd19e8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
@@ -2,44 +2,44 @@
 
 Set timer for test function.
 Call stack:
-    0) stop (frameworks-step-into-skips-setTimeout.js:35)
-    1) callback (frameworks-step-into-skips-setTimeout.js:29)
+    0) stop (frameworks-step-into-skips-setTimeout.js:37)
+    1) callback (frameworks-step-into-skips-setTimeout.js:31)
   * 2) Framework_scheduleUntilDone (framework.js:142)
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
   * 1) Framework.scheduleUntilDone (framework.js:138)
-    2) testFunction (frameworks-step-into-skips-setTimeout.js:22)
+    2) testFunction (frameworks-step-into-skips-setTimeout.js:24)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepOut...
 Call stack:
-    0) callback (frameworks-step-into-skips-setTimeout.js:30)
+    0) callback (frameworks-step-into-skips-setTimeout.js:32)
   * 1) Framework_scheduleUntilDone (framework.js:142)
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
   * 1) Framework.scheduleUntilDone (framework.js:138)
-    2) testFunction (frameworks-step-into-skips-setTimeout.js:22)
+    2) testFunction (frameworks-step-into-skips-setTimeout.js:24)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepInto...
 Call stack:
-    0) callback (frameworks-step-into-skips-setTimeout.js:30)
+    0) callback (frameworks-step-into-skips-setTimeout.js:32)
   * 1) Framework_scheduleUntilDone (framework.js:142)
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
   * 1) Framework.scheduleUntilDone (framework.js:138)
-    2) testFunction (frameworks-step-into-skips-setTimeout.js:22)
+    2) testFunction (frameworks-step-into-skips-setTimeout.js:24)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepInto...
 Call stack:
-    0) callback (frameworks-step-into-skips-setTimeout.js:27)
+    0) callback (frameworks-step-into-skips-setTimeout.js:29)
   * 1) Framework_scheduleUntilDone (framework.js:142)
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
@@ -47,7 +47,7 @@
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
   * 1) Framework.scheduleUntilDone (framework.js:138)
-    2) testFunction (frameworks-step-into-skips-setTimeout.js:22)
+    2) testFunction (frameworks-step-into-skips-setTimeout.js:24)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout.js
index 8c93acc..92606cc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(
       `Tests that stepping into blackboxed framework will not pause on setTimeout() inside the framework.\n`);
@@ -37,7 +39,7 @@
   `);
 
   var frameworkRegexString = '/framework\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.startDebuggerTest(step1, true);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-steppings-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-steppings-expected.txt
index f986552b..19ca137 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-steppings-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-steppings-expected.txt
@@ -2,7 +2,7 @@
 
 Set timer for test function.
 Call stack:
-    0) testFunction (frameworks-steppings.js:19)
+    0) testFunction (frameworks-steppings.js:21)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
@@ -10,49 +10,49 @@
 Executing StepInto...
 Executing StepInto...
 Call stack:
-    0) callback1 (frameworks-steppings.js:21)
+    0) callback1 (frameworks-steppings.js:23)
   * 1) Framework.safeRun (framework.js:8)
-    2) testFunction (frameworks-steppings.js:20)
+    2) testFunction (frameworks-steppings.js:22)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepInto...
 Call stack:
-    0) callback2 (frameworks-steppings.js:27)
+    0) callback2 (frameworks-steppings.js:29)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:10)
-    3) callback1 (frameworks-steppings.js:21)
+    3) callback1 (frameworks-steppings.js:23)
   * 4) Framework.safeRun (framework.js:8)
-    5) testFunction (frameworks-steppings.js:20)
+    5) testFunction (frameworks-steppings.js:22)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepInto...
 Call stack:
-    0) callback2 (frameworks-steppings.js:28)
+    0) callback2 (frameworks-steppings.js:30)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:10)
-    3) callback1 (frameworks-steppings.js:21)
+    3) callback1 (frameworks-steppings.js:23)
   * 4) Framework.safeRun (framework.js:8)
-    5) testFunction (frameworks-steppings.js:20)
+    5) testFunction (frameworks-steppings.js:22)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepInto...
 Call stack:
-    0) callback3 (frameworks-steppings.js:33)
+    0) callback3 (frameworks-steppings.js:35)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:13)
   * 3) Framework.safeRun (framework.js:10)
-    4) callback2 (frameworks-steppings.js:28)
+    4) callback2 (frameworks-steppings.js:30)
   * 5) Framework.safeRun (framework.js:8)
   * 6) Framework.safeRun (framework.js:10)
-    7) callback1 (frameworks-steppings.js:21)
+    7) callback1 (frameworks-steppings.js:23)
   * 8) Framework.safeRun (framework.js:8)
-    9) testFunction (frameworks-steppings.js:20)
+    9) testFunction (frameworks-steppings.js:22)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
@@ -62,45 +62,45 @@
 Executing StepInto...
 Executing StepInto...
 Call stack:
-    0) callback4 (frameworks-steppings.js:41)
+    0) callback4 (frameworks-steppings.js:43)
   * 1) Framework_bound (framework.js:105)
   * 2) Framework_bound (framework.js:105)
   * 3) Framework_bound (framework.js:105)
   * 4) Framework.safeRun (framework.js:8)
-    5) callback3 (frameworks-steppings.js:36)
+    5) callback3 (frameworks-steppings.js:38)
   * 6) Framework.safeRun (framework.js:8)
   * 7) Framework.safeRun (framework.js:13)
   * 8) Framework.safeRun (framework.js:10)
-    9) callback2 (frameworks-steppings.js:28)
+    9) callback2 (frameworks-steppings.js:30)
   * 10) Framework.safeRun (framework.js:8)
   * 11) Framework.safeRun (framework.js:10)
-    12) callback1 (frameworks-steppings.js:21)
+    12) callback1 (frameworks-steppings.js:23)
   * 13) Framework.safeRun (framework.js:8)
-    14) testFunction (frameworks-steppings.js:20)
+    14) testFunction (frameworks-steppings.js:22)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepInto...
 Call stack:
-    0)  (frameworks-steppings.js:42)
+    0)  (frameworks-steppings.js:44)
   * 1) Framework.safeRun (framework.js:8)
   * 2) Framework.safeRun (framework.js:10)
-    3) callback4 (frameworks-steppings.js:41)
+    3) callback4 (frameworks-steppings.js:43)
   * 4) Framework_bound (framework.js:105)
   * 5) Framework_bound (framework.js:105)
   * 6) Framework_bound (framework.js:105)
   * 7) Framework.safeRun (framework.js:8)
-    8) callback3 (frameworks-steppings.js:36)
+    8) callback3 (frameworks-steppings.js:38)
   * 9) Framework.safeRun (framework.js:8)
   * 10) Framework.safeRun (framework.js:13)
   * 11) Framework.safeRun (framework.js:10)
-    12) callback2 (frameworks-steppings.js:28)
+    12) callback2 (frameworks-steppings.js:30)
   * 13) Framework.safeRun (framework.js:8)
   * 14) Framework.safeRun (framework.js:10)
-    15) callback1 (frameworks-steppings.js:21)
+    15) callback1 (frameworks-steppings.js:23)
   * 16) Framework.safeRun (framework.js:8)
-    17) testFunction (frameworks-steppings.js:20)
+    17) testFunction (frameworks-steppings.js:22)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
@@ -108,79 +108,79 @@
 Executing StepInto...
 Executing StepInto...
 Call stack:
-    0) callback4 (frameworks-steppings.js:45)
-  * 1) Framework_bound (framework.js:105)
-  * 2) Framework_bound (framework.js:105)
-  * 3) Framework_bound (framework.js:105)
-  * 4) Framework.safeRun (framework.js:8)
-    5) callback3 (frameworks-steppings.js:36)
-  * 6) Framework.safeRun (framework.js:8)
-  * 7) Framework.safeRun (framework.js:13)
-  * 8) Framework.safeRun (framework.js:10)
-    9) callback2 (frameworks-steppings.js:28)
-  * 10) Framework.safeRun (framework.js:8)
-  * 11) Framework.safeRun (framework.js:10)
-    12) callback1 (frameworks-steppings.js:21)
-  * 13) Framework.safeRun (framework.js:8)
-    14) testFunction (frameworks-steppings.js:20)
-    [setTimeout]
-    0) scheduleTestFunction <omitted>
-    <... skipped remaining frames ...>
-
-Executing StepInto...
-Call stack:
     0) callback4 (frameworks-steppings.js:47)
   * 1) Framework_bound (framework.js:105)
   * 2) Framework_bound (framework.js:105)
   * 3) Framework_bound (framework.js:105)
   * 4) Framework.safeRun (framework.js:8)
-    5) callback3 (frameworks-steppings.js:36)
+    5) callback3 (frameworks-steppings.js:38)
   * 6) Framework.safeRun (framework.js:8)
   * 7) Framework.safeRun (framework.js:13)
   * 8) Framework.safeRun (framework.js:10)
-    9) callback2 (frameworks-steppings.js:28)
+    9) callback2 (frameworks-steppings.js:30)
   * 10) Framework.safeRun (framework.js:8)
   * 11) Framework.safeRun (framework.js:10)
-    12) callback1 (frameworks-steppings.js:21)
+    12) callback1 (frameworks-steppings.js:23)
   * 13) Framework.safeRun (framework.js:8)
-    14) testFunction (frameworks-steppings.js:20)
-    [setTimeout]
-    0) scheduleTestFunction <omitted>
-    <... skipped remaining frames ...>
-
-Executing StepOut...
-Call stack:
-    0) callback3 (frameworks-steppings.js:37)
-  * 1) Framework.safeRun (framework.js:8)
-  * 2) Framework.safeRun (framework.js:13)
-  * 3) Framework.safeRun (framework.js:10)
-    4) callback2 (frameworks-steppings.js:28)
-  * 5) Framework.safeRun (framework.js:8)
-  * 6) Framework.safeRun (framework.js:10)
-    7) callback1 (frameworks-steppings.js:21)
-  * 8) Framework.safeRun (framework.js:8)
-    9) testFunction (frameworks-steppings.js:20)
-    [setTimeout]
-    0) scheduleTestFunction <omitted>
-    <... skipped remaining frames ...>
-
-Executing StepOver...
-Call stack:
-    0) callback2 (frameworks-steppings.js:29)
-  * 1) Framework.safeRun (framework.js:8)
-  * 2) Framework.safeRun (framework.js:10)
-    3) callback1 (frameworks-steppings.js:21)
-  * 4) Framework.safeRun (framework.js:8)
-    5) testFunction (frameworks-steppings.js:20)
+    14) testFunction (frameworks-steppings.js:22)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Executing StepInto...
 Call stack:
-    0) callback1 (frameworks-steppings.js:22)
+    0) callback4 (frameworks-steppings.js:49)
+  * 1) Framework_bound (framework.js:105)
+  * 2) Framework_bound (framework.js:105)
+  * 3) Framework_bound (framework.js:105)
+  * 4) Framework.safeRun (framework.js:8)
+    5) callback3 (frameworks-steppings.js:38)
+  * 6) Framework.safeRun (framework.js:8)
+  * 7) Framework.safeRun (framework.js:13)
+  * 8) Framework.safeRun (framework.js:10)
+    9) callback2 (frameworks-steppings.js:30)
+  * 10) Framework.safeRun (framework.js:8)
+  * 11) Framework.safeRun (framework.js:10)
+    12) callback1 (frameworks-steppings.js:23)
+  * 13) Framework.safeRun (framework.js:8)
+    14) testFunction (frameworks-steppings.js:22)
+    [setTimeout]
+    0) scheduleTestFunction <omitted>
+    <... skipped remaining frames ...>
+
+Executing StepOut...
+Call stack:
+    0) callback3 (frameworks-steppings.js:39)
   * 1) Framework.safeRun (framework.js:8)
-    2) testFunction (frameworks-steppings.js:20)
+  * 2) Framework.safeRun (framework.js:13)
+  * 3) Framework.safeRun (framework.js:10)
+    4) callback2 (frameworks-steppings.js:30)
+  * 5) Framework.safeRun (framework.js:8)
+  * 6) Framework.safeRun (framework.js:10)
+    7) callback1 (frameworks-steppings.js:23)
+  * 8) Framework.safeRun (framework.js:8)
+    9) testFunction (frameworks-steppings.js:22)
+    [setTimeout]
+    0) scheduleTestFunction <omitted>
+    <... skipped remaining frames ...>
+
+Executing StepOver...
+Call stack:
+    0) callback2 (frameworks-steppings.js:31)
+  * 1) Framework.safeRun (framework.js:8)
+  * 2) Framework.safeRun (framework.js:10)
+    3) callback1 (frameworks-steppings.js:23)
+  * 4) Framework.safeRun (framework.js:8)
+    5) testFunction (frameworks-steppings.js:22)
+    [setTimeout]
+    0) scheduleTestFunction <omitted>
+    <... skipped remaining frames ...>
+
+Executing StepInto...
+Call stack:
+    0) callback1 (frameworks-steppings.js:24)
+  * 1) Framework.safeRun (framework.js:8)
+    2) testFunction (frameworks-steppings.js:22)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-steppings.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-steppings.js
index d05453c..9e8cee1 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-steppings.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-steppings.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests stepping into/over/out with framework black-boxing.\n`);
   await TestRunner.loadLegacyModule('sources');
@@ -50,7 +52,7 @@
   `);
 
   var frameworkRegexString = '/framework\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.startDebuggerTest(step1, true);
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-async-callstack-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-async-callstack-expected.txt
index 4de7f3c..2a3770be 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-async-callstack-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-async-callstack-expected.txt
@@ -2,12 +2,12 @@
 
 Set timer for test function.
 Call stack:
-    0) callback2 (frameworks-with-async-callstack.js:39)
+    0) callback2 (frameworks-with-async-callstack.js:41)
   * 1) Framework_inner1 (framework.js:59)
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
   * 1) Framework_willSchedule (framework.js:51)
-    2) window.callbackFromFramework (frameworks-with-async-callstack.js:19)
+    2) window.callbackFromFramework (frameworks-with-async-callstack.js:21)
   * 3) Framework_inner2 (framework.js:63)
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
@@ -15,26 +15,26 @@
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
   * 1) Framework.doSomeAsyncChainCalls (framework.js:67)
-    2) callback1 (frameworks-with-async-callstack.js:34)
+    2) callback1 (frameworks-with-async-callstack.js:36)
   * 3) Framework.safeRun (framework.js:8)
   * 4) Framework.safeRun (framework.js:10)
-    5) timeout1 (frameworks-with-async-callstack.js:29)
+    5) timeout1 (frameworks-with-async-callstack.js:31)
     [setTimeout]
-    0) testFunction (frameworks-with-async-callstack.js:24)
+    0) testFunction (frameworks-with-async-callstack.js:26)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Printing visible call stack:
 Call stack:
-    0) callback2 (frameworks-with-async-callstack.js:39)
+    0) callback2 (frameworks-with-async-callstack.js:41)
     [setTimeout]
-    0) window.callbackFromFramework (frameworks-with-async-callstack.js:19)
+    0) window.callbackFromFramework (frameworks-with-async-callstack.js:21)
     [setTimeout]
-    0) callback1 (frameworks-with-async-callstack.js:34)
-    1) timeout1 (frameworks-with-async-callstack.js:29)
+    0) callback1 (frameworks-with-async-callstack.js:36)
+    1) timeout1 (frameworks-with-async-callstack.js:31)
     [setTimeout]
-    0) testFunction (frameworks-with-async-callstack.js:24)
+    0) testFunction (frameworks-with-async-callstack.js:26)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-async-callstack.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-async-callstack.js
index 0df2ce1a..14b98d1f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-async-callstack.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-async-callstack.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests the async call stacks and framework black-boxing features working together.\n`);
   await TestRunner.loadLegacyModule('sources');
@@ -43,7 +45,7 @@
   var frameworkRegexString = '/framework\\.js$';
   var maxAsyncCallStackDepth = 8;
 
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.setQuiet(true);
   SourcesTestRunner.startDebuggerTest(step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-worker.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-worker.js
index 304b9f9e..075d4f8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-worker.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-frameworks/frameworks-with-worker.js
@@ -5,6 +5,8 @@
 import {TestRunner} from 'test_runner';
 import {SourcesTestRunner} from 'sources_test_runner';
 
+import * as Common from 'devtools/core/common/common.js';
+
 (async function() {
   TestRunner.addResult(`Tests that blackboxed script will be skipped while stepping on worker.\n`);
   await TestRunner.loadLegacyModule('sources');
@@ -17,7 +19,7 @@
   `);
 
   var frameworkRegexString = 'foo\\.js$';
-  Common.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
+  Common.Settings.settingForTest('skipStackFramesPattern').set(frameworkRegexString);
 
   SourcesTestRunner.startDebuggerTest(step1, true);
   function step1() {
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index cdc059d..fb68b93 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -6585,17 +6585,6 @@
     attribute @@toStringTag
     getter node
     method constructor
-interface NotRestoredReasons
-    attribute @@toStringTag
-    getter children
-    getter id
-    getter name
-    getter preventedBackForwardCache
-    getter reasons
-    getter src
-    getter url
-    method constructor
-    method toJSON
 interface Notification : EventTarget
     static getter maxActions
     static getter permission
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index 85178a88..c4b6c62 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -390,7 +390,7 @@
 </histogram>
 
 <histogram name="Arc.App.LowMemoryKills.{ArcAppKillType}Count10Minutes"
-    units="Apps" expires_after="2023-04-07">
+    units="Apps" expires_after="2024-02-20">
   <owner>cwd@google.com</owner>
   <owner>cros-vm-technology@google.com</owner>
   <summary>
@@ -402,7 +402,7 @@
 
 <histogram
     name="Arc.App.LowMemoryKills.{ArcBackgroundVms}.{ArcAppKillType}Count10Minutes"
-    units="Apps" expires_after="2023-04-07">
+    units="Apps" expires_after="2024-02-20">
   <owner>cwd@google.com</owner>
   <owner>cros-vm-technology@google.com</owner>
   <summary>
@@ -415,7 +415,7 @@
 
 <histogram
     name="Arc.App.LowMemoryKills{ArcAppKillDailyBackgroundVms}{ArcAppKillDailyType}"
-    units="Apps" expires_after="2023-09-29">
+    units="Apps" expires_after="2024-02-20">
   <owner>cwd@google.com</owner>
   <owner>cros-vm-technology@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index dbc6740..85d591b 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -1350,6 +1350,27 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Extensions.Events.DispatchToSendToRenderer.{BackgroundContextType}"
+    units="microseconds" expires_after="2024-08-18">
+  <owner>jlulejian@chromium.org</owner>
+  <owner>extensions-core@chromium.org</owner>
+  <summary>
+    Records the time it took for the event to start dispatch in the event
+    router, until it is dispatched to the renderer for background context of
+    type {BackgroundContextType}. Emitted in the browser immediately after the
+    dispatch has been sent to the renderer layer. Values are capped at 5 minutes
+    maximum to be in line with other dispatch time related metrics. This is
+    recorded only for clients with high-resolution clocks.
+  </summary>
+  <token key="BackgroundContextType">
+    <variant name="ExtensionEventPage" summary="event page"/>
+    <variant name="ExtensionPersistentBackgroundPage"
+        summary="persistent background page"/>
+    <variant name="ExtensionServiceWorker" summary="service worker"/>
+  </token>
+</histogram>
+
 <histogram name="Extensions.Events.DispatchWithPersistentBackgroundPage"
     enum="ExtensionEvents" expires_after="never">
 <!-- expires-never: Monitoring core extensions platform behavior. -->
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index 4a2f2d9..24d9feb8 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1716,7 +1716,7 @@
 
 <histogram
     name="Prerender.Experimental.BookmarkBar.EnterToPressDuration{ButtonType}"
-    units="ms" expires_after="2023-09-24">
+    units="ms" expires_after="2024-02-24">
   <owner>robertlin@chromium.org</owner>
   <owner>toyoshim@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
@@ -1732,7 +1732,7 @@
 
 <histogram
     name="Prerender.Experimental.BookmarkBar.HoverDuration{OriginType}.{ConversionResultType}"
-    units="ms" expires_after="2023-09-24">
+    units="ms" expires_after="2024-02-24">
   <owner>robertlin@chromium.org</owner>
   <owner>toyoshim@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h
index 0f7cbf6b..f080d65b 100644
--- a/ui/aura/client/aura_constants.h
+++ b/ui/aura/client/aura_constants.h
@@ -30,6 +30,7 @@
 constexpr int kResizeBehaviorCanResize = 1 << 0;
 constexpr int kResizeBehaviorCanMaximize = 1 << 1;
 constexpr int kResizeBehaviorCanMinimize = 1 << 2;
+constexpr int kResizeBehaviorCanFullscreen = 1 << 3;
 
 // A value used to represent an unassigned workspace for `kWindowWorkspaceKey`.
 constexpr int kWindowWorkspaceUnassignedWorkspace = -1;
diff --git a/ui/aura/test/test_windows.cc b/ui/aura/test/test_windows.cc
index f13aa39..bba32c4 100644
--- a/ui/aura/test/test_windows.cc
+++ b/ui/aura/test/test_windows.cc
@@ -50,9 +50,10 @@
   Window* window = new Window(delegate, type);
   window->SetId(id);
   window->Init(ui::LAYER_TEXTURED);
-  window->SetProperty(
-      client::kResizeBehaviorKey,
-      client::kResizeBehaviorCanResize | client::kResizeBehaviorCanMaximize);
+  window->SetProperty(client::kResizeBehaviorKey,
+                      client::kResizeBehaviorCanResize |
+                          client::kResizeBehaviorCanMaximize |
+                          client::kResizeBehaviorCanFullscreen);
   window->SetBounds(bounds);
   if (show_on_creation)
     window->Show();
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index f10ce0d..c7c1496d 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -1031,7 +1031,6 @@
   if (!texture_layer_.get()) {
     scoped_refptr<cc::TextureLayer> new_layer =
         cc::TextureLayer::CreateForMailbox(this);
-    new_layer->SetFlipped(true);
     if (!SwitchToLayer(new_layer))
       return;
 
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index e3b8239..f6cad0b4 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -414,7 +414,8 @@
   void SetName(const std::string& name);
 
   // Set new TransferableResource for this layer. This method only supports
-  // a gpu-backed |resource|.
+  // a gpu-backed |resource| which is assumed to have top-left origin. Clients
+  // should call SetTextureFlipped(true) for bottom-left origin resources.
   void SetTransferableResource(const viz::TransferableResource& resource,
                                viz::ReleaseCallback release_callback,
                                gfx::Size texture_size_in_dip);
diff --git a/ui/file_manager/file_manager/foreground/js/android_app_list_model.js b/ui/file_manager/file_manager/foreground/js/android_app_list_model.js
index 167f3e9..432436b2 100644
--- a/ui/file_manager/file_manager/foreground/js/android_app_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/android_app_list_model.js
@@ -4,7 +4,7 @@
 
 import {NativeEventTarget as EventTarget} from 'chrome://resources/ash/common/event_target.js';
 
-import {addAndroidApps} from '../../state/actions/android_apps.js';
+import {addAndroidApps} from '../../state/ducks/android_apps.js';
 import {getStore} from '../../state/store.js';
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
index a15d741..30cc8c1a 100644
--- a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
+++ b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
@@ -10,7 +10,7 @@
 import {metrics} from '../../common/js/metrics.js';
 import {util} from '../../common/js/util.js';
 import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
-import {addFolderShortcut, refreshFolderShortcut, removeFolderShortcut} from '../../state/actions/folder_shortcuts.js';
+import {addFolderShortcut, refreshFolderShortcut, removeFolderShortcut} from '../../state/ducks/folder_shortcuts.js';
 import {getStore} from '../../state/store.js';
 
 /**
diff --git a/ui/file_manager/file_manager/state/actions.ts b/ui/file_manager/file_manager/state/actions.ts
index 20e3526..70c7928 100644
--- a/ui/file_manager/file_manager/state/actions.ts
+++ b/ui/file_manager/file_manager/state/actions.ts
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 import {AddChildEntriesAction, ClearStaleCachedEntriesAction, UpdateMetadataAction} from './actions/all_entries.js';
-import {AddAndroidAppsAction} from './actions/android_apps.js';
+import {AddAndroidAppsAction} from './ducks/android_apps.js';
 import {ChangeDirectoryAction, ChangeFileTasksAction, ChangeSelectionAction, UpdateDirectoryContentAction} from './actions/current_directory.js';
-import {AddFolderShortcutAction, RefreshFolderShortcutAction, RemoveFolderShortcutAction} from './actions/folder_shortcuts.js';
+import {AddFolderShortcutAction, RefreshFolderShortcutAction, RemoveFolderShortcutAction} from './ducks/folder_shortcuts.js';
 import {RefreshNavigationRootsAction, UpdateNavigationEntryAction} from './actions/navigation.js';
 import {UpdatePreferencesAction} from './actions/preferences.js';
 import {UpdateBulkPinProgressAction} from './ducks/bulk_pinning.js';
diff --git a/ui/file_manager/file_manager/state/actions/android_apps.ts b/ui/file_manager/file_manager/state/actions/android_apps.ts
deleted file mode 100644
index 9eef29a..0000000
--- a/ui/file_manager/file_manager/state/actions/android_apps.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {BaseAction} from '../../lib/base_store.js';
-import {ActionType} from '../actions.js';
-
-/**
- * Actions for Android apps.
- *
- * Android App is something we get from private API
- * `chrome.fileManagerPrivate.getAndroidPickerApps`, it will be shown as
- * a directory item in FilePicker mode.
- */
-
-/** Action to add all android app config to the store. */
-export interface AddAndroidAppsAction extends BaseAction {
-  type: ActionType.ADD_ANDROID_APPS;
-  payload: {
-    apps: chrome.fileManagerPrivate.AndroidApp[],
-  };
-}
-
-/** Action factory to add all android app config to the store. */
-export function addAndroidApps(payload: AddAndroidAppsAction['payload']):
-    AddAndroidAppsAction {
-  return {
-    type: ActionType.ADD_ANDROID_APPS,
-    payload,
-  };
-}
diff --git a/ui/file_manager/file_manager/state/actions/folder_shortcuts.ts b/ui/file_manager/file_manager/state/actions/folder_shortcuts.ts
deleted file mode 100644
index 55079ab..0000000
--- a/ui/file_manager/file_manager/state/actions/folder_shortcuts.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {FileKey} from '../../externs/ts/state.js';
-import {BaseAction} from '../../lib/base_store.js';
-import {ActionType} from '../actions.js';
-
-/**
- * Actions for Folder shortcuts.
- *
- * Folder shortcuts represent a shortcut for the folders inside Drive.
- */
-
-/** Action to refresh all folder shortcuts in the store. */
-export interface RefreshFolderShortcutAction extends BaseAction {
-  type: ActionType.REFRESH_FOLDER_SHORTCUT;
-  payload: {
-    /** All folder shortcuts should be provided here. */
-    entries: DirectoryEntry[],
-  };
-}
-
-/** Action to add single folder shortcut in the store. */
-export interface AddFolderShortcutAction extends BaseAction {
-  type: ActionType.ADD_FOLDER_SHORTCUT;
-  payload: {
-    entry: DirectoryEntry,
-  };
-}
-
-/** Action to remove single folder shortcut from the store. */
-export interface RemoveFolderShortcutAction extends BaseAction {
-  type: ActionType.REMOVE_FOLDER_SHORTCUT;
-  payload: {
-    key: FileKey,
-  };
-}
-
-/**
- * Action factory to refresh all folder shortcuts in the store, all folder
- * shortcuts needs to be provided here because it will replace all existing ones
- * in the store.
- */
-export function refreshFolderShortcut(
-    payload: RefreshFolderShortcutAction['payload']):
-    RefreshFolderShortcutAction {
-  return {
-    type: ActionType.REFRESH_FOLDER_SHORTCUT,
-    payload,
-  };
-}
-
-/** Action factory to add single folder shortcut in the store. */
-export function addFolderShortcut(payload: AddFolderShortcutAction['payload']):
-    AddFolderShortcutAction {
-  return {
-    type: ActionType.ADD_FOLDER_SHORTCUT,
-    payload,
-  };
-}
-
-/** Action factory to remove single folder shortcut in the store. */
-export function removeFolderShortcut(
-    payload: RemoveFolderShortcutAction['payload']):
-    RemoveFolderShortcutAction {
-  return {
-    type: ActionType.REMOVE_FOLDER_SHORTCUT,
-    payload,
-  };
-}
diff --git a/ui/file_manager/file_manager/state/ducks/android_apps.ts b/ui/file_manager/file_manager/state/ducks/android_apps.ts
new file mode 100644
index 0000000..046c91a
--- /dev/null
+++ b/ui/file_manager/file_manager/state/ducks/android_apps.ts
@@ -0,0 +1,52 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {State} from '../../externs/ts/state.js';
+import {addReducer, BaseAction, Reducer, ReducersMap} from '../../lib/base_store.js';
+import {Action, ActionType} from '../actions.js';
+
+/**
+ * @fileoverview Reducer for android apps.
+ *
+ * This file is checked via TS, so we suppress Closure checks.
+ * @suppress {checkTypes}
+ */
+
+/**
+ * Actions and reducers for Android apps.
+ *
+ * Android App is something we get from private API
+ * `chrome.fileManagerPrivate.getAndroidPickerApps`, it will be shown as
+ * a directory item in FilePicker mode.
+ */
+
+/** Map of actions to reducers for the bulk pinning slice. */
+export const androidAppsReducersMap: ReducersMap<State, Action> = new Map();
+
+/** Action to add all android app config to the store. */
+export interface AddAndroidAppsAction extends BaseAction {
+  type: ActionType.ADD_ANDROID_APPS;
+  payload: {
+    apps: chrome.fileManagerPrivate.AndroidApp[],
+  };
+}
+
+function addAndroidAppsReducer(
+    currentState: State, payload: AddAndroidAppsAction['payload']): State {
+  const {apps} = payload;
+
+  const androidApps: Record<string, chrome.fileManagerPrivate.AndroidApp> = {};
+  for (const app of apps) {
+    androidApps[app.packageName] = app;
+  }
+  return {
+    ...currentState,
+    androidApps,
+  };
+}
+
+/** Action factory to add all android app config to the store. */
+export const addAndroidApps = addReducer(
+    ActionType.ADD_ANDROID_APPS,
+    addAndroidAppsReducer as Reducer<State, Action>, androidAppsReducersMap);
diff --git a/ui/file_manager/file_manager/state/reducers/android_apps_unittest.ts b/ui/file_manager/file_manager/state/ducks/android_apps_unittest.ts
similarity index 95%
rename from ui/file_manager/file_manager/state/reducers/android_apps_unittest.ts
rename to ui/file_manager/file_manager/state/ducks/android_apps_unittest.ts
index 0c41351..786b203 100644
--- a/ui/file_manager/file_manager/state/reducers/android_apps_unittest.ts
+++ b/ui/file_manager/file_manager/state/ducks/android_apps_unittest.ts
@@ -6,9 +6,10 @@
 import '../store.js';
 
 import {State} from '../../externs/ts/state.js';
-import {addAndroidApps} from '../actions/android_apps.js';
 import {setupStore, waitDeepEquals} from '../for_tests.js';
 
+import {addAndroidApps} from './android_apps.js';
+
 /** Tests that android apps can be added correctly to the store. */
 export async function testAddAndroidApps(done: () => void) {
   const androidApps: chrome.fileManagerPrivate.AndroidApp[] = [
diff --git a/ui/file_manager/file_manager/state/ducks/folder_shortcuts.ts b/ui/file_manager/file_manager/state/ducks/folder_shortcuts.ts
new file mode 100644
index 0000000..c5fb7b04
--- /dev/null
+++ b/ui/file_manager/file_manager/state/ducks/folder_shortcuts.ts
@@ -0,0 +1,125 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {util} from '../../common/js/util.js';
+import {FileKey, State} from '../../externs/ts/state.js';
+import {addReducer, BaseAction, Reducer, ReducersMap} from '../../lib/base_store.js';
+import {Action, ActionType} from '../actions.js';
+import {getEntry} from '../store.js';
+
+/**
+ * Actions and reducers for folder shortcuts.
+ *
+ * Folder shortcuts represent a shortcut for the folders inside Drive.
+ */
+
+/** Map of actions to reducers for the folder shortcuts slice. */
+export const folderShortcutsReducersMap: ReducersMap<State, Action> = new Map();
+
+/** Action to refresh all folder shortcuts in the store. */
+export interface RefreshFolderShortcutAction extends BaseAction {
+  type: ActionType.REFRESH_FOLDER_SHORTCUT;
+  payload: {
+    /** All folder shortcuts should be provided here. */
+    entries: DirectoryEntry[],
+  };
+}
+
+const refreshFolderShortcutReducer =
+    (currentState: State, payload: RefreshFolderShortcutAction['payload']):
+        State => ({
+          ...currentState,
+          folderShortcuts: payload.entries.map(entry => entry.toURL()),
+        });
+
+/**
+ * Action factory to refresh all folder shortcuts in the store, all folder
+ * shortcuts needs to be provided here because it will replace all existing ones
+ * in the store.
+ */
+export const refreshFolderShortcut = addReducer(
+    ActionType.REFRESH_FOLDER_SHORTCUT,
+    refreshFolderShortcutReducer as Reducer<State, Action>,
+    folderShortcutsReducersMap);
+
+
+/** Action to add single folder shortcut in the store. */
+export interface AddFolderShortcutAction extends BaseAction {
+  type: ActionType.ADD_FOLDER_SHORTCUT;
+  payload: {
+    entry: DirectoryEntry,
+  };
+}
+
+function addFolderShortcutReducer(
+    currentState: State, payload: AddFolderShortcutAction['payload']): State {
+  const {entry} = payload;
+  const key = entry.toURL();
+  const {folderShortcuts} = currentState;
+
+  for (let i = 0; i < folderShortcuts.length; i++) {
+    // Do nothing if the key is already existed.
+    if (key === folderShortcuts[i]) {
+      return currentState;
+    }
+
+    const shortcutEntry = getEntry(currentState, folderShortcuts[i]!);
+    // The folder shortcut array is sorted, the new item will be added just
+    // before the first larger item.
+    if (util.comparePath(shortcutEntry!, entry) > 0) {
+      return {
+        ...currentState,
+        folderShortcuts: [
+          ...folderShortcuts.slice(0, i),
+          key,
+          ...folderShortcuts.slice(i),
+        ],
+      };
+    }
+  }
+
+  // If for loop is not returned, the key is not added yet, add it at the last.
+  return {
+    ...currentState,
+    folderShortcuts: folderShortcuts.concat(key),
+  };
+}
+
+/** Action factory to add single folder shortcut in the store. */
+export const addFolderShortcut = addReducer(
+    ActionType.ADD_FOLDER_SHORTCUT,
+    addFolderShortcutReducer as Reducer<State, Action>,
+    folderShortcutsReducersMap);
+
+
+/** Action to remove single folder shortcut from the store. */
+export interface RemoveFolderShortcutAction extends BaseAction {
+  type: ActionType.REMOVE_FOLDER_SHORTCUT;
+  payload: {
+    key: FileKey,
+  };
+}
+
+function removeFolderShortcutReducer(
+    currentState: State,
+    payload: RemoveFolderShortcutAction['payload']): State {
+  const {key} = payload;
+  const {folderShortcuts} = currentState;
+  const isExisted = folderShortcuts.find(k => k === key);
+  // Do nothing if the key is not existed.
+  if (!isExisted) {
+    return currentState;
+  }
+
+  return {
+    ...currentState,
+    folderShortcuts: folderShortcuts.filter(k => k !== key),
+  };
+}
+
+/** Action factory to remove single folder shortcut in the store. */
+export const removeFolderShortcut = addReducer(
+    ActionType.REMOVE_FOLDER_SHORTCUT,
+    removeFolderShortcutReducer as Reducer<State, Action>,
+    folderShortcutsReducersMap);
diff --git a/ui/file_manager/file_manager/state/reducers/folder_shortcuts_unittest.ts b/ui/file_manager/file_manager/state/ducks/folder_shortcuts_unittest.ts
similarity index 98%
rename from ui/file_manager/file_manager/state/reducers/folder_shortcuts_unittest.ts
rename to ui/file_manager/file_manager/state/ducks/folder_shortcuts_unittest.ts
index 985c3f50..46fd22c 100644
--- a/ui/file_manager/file_manager/state/reducers/folder_shortcuts_unittest.ts
+++ b/ui/file_manager/file_manager/state/ducks/folder_shortcuts_unittest.ts
@@ -7,11 +7,11 @@
 
 import {MockFileSystem} from '../../common/js/mock_entry.js';
 import {State} from '../../externs/ts/state.js';
-import {addFolderShortcut, refreshFolderShortcut, removeFolderShortcut} from '../actions/folder_shortcuts.js';
 import {setUpFileManagerOnWindow, setupStore, waitDeepEquals} from '../for_tests.js';
+import {convertEntryToFileData} from '../reducers/all_entries.js';
 import {getEmptyState} from '../store.js';
 
-import {convertEntryToFileData} from './all_entries.js';
+import {addFolderShortcut, refreshFolderShortcut, removeFolderShortcut} from './folder_shortcuts.js';
 
 export function setUp() {
   setUpFileManagerOnWindow();
diff --git a/ui/file_manager/file_manager/state/reducers/android_apps.ts b/ui/file_manager/file_manager/state/reducers/android_apps.ts
deleted file mode 100644
index 439fccf3..0000000
--- a/ui/file_manager/file_manager/state/reducers/android_apps.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Reducer for android apps.
- *
- * This file is checked via TS, so we suppress Closure checks.
- * @suppress {checkTypes}
- */
-
-import {State} from '../../externs/ts/state.js';
-import {AddAndroidAppsAction} from '../actions/android_apps.js';
-
-export function addAndroidApps(
-    currentState: State, action: AddAndroidAppsAction): State {
-  const {apps} = action.payload;
-
-  const androidApps: Record<string, chrome.fileManagerPrivate.AndroidApp> = {};
-  for (const app of apps) {
-    androidApps[app.packageName] = app;
-  }
-  return {
-    ...currentState,
-    androidApps,
-  };
-}
diff --git a/ui/file_manager/file_manager/state/reducers/folder_shortcuts.ts b/ui/file_manager/file_manager/state/reducers/folder_shortcuts.ts
deleted file mode 100644
index c70948ce..0000000
--- a/ui/file_manager/file_manager/state/reducers/folder_shortcuts.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {util} from '../../common/js/util.js';
-import {State} from '../../externs/ts/state.js';
-import {AddFolderShortcutAction, RefreshFolderShortcutAction, RemoveFolderShortcutAction} from '../actions/folder_shortcuts.js';
-import {getEntry} from '../store.js';
-
-export function refreshFolderShortcut(
-    currentState: State, action: RefreshFolderShortcutAction): State {
-  const {entries} = action.payload;
-
-  return {
-    ...currentState,
-    folderShortcuts: entries.map(entry => entry.toURL()),
-  };
-}
-
-export function addFolderShortcut(
-    currentState: State, action: AddFolderShortcutAction): State {
-  const {entry} = action.payload;
-  const key = entry.toURL();
-  const {folderShortcuts} = currentState;
-
-  for (let i = 0; i < folderShortcuts.length; i++) {
-    // Do nothing if the key is already existed.
-    if (key === folderShortcuts[i]) {
-      return currentState;
-    }
-
-    const shortcutEntry = getEntry(currentState, folderShortcuts[i]!);
-    // The folder shortcut array is sorted, the new item will be added just
-    // before the first larger item.
-    if (util.comparePath(shortcutEntry!, entry) > 0) {
-      return {
-        ...currentState,
-        folderShortcuts: [
-          ...folderShortcuts.slice(0, i),
-          key,
-          ...folderShortcuts.slice(i),
-        ],
-      };
-    }
-  }
-
-  // If for loop is not returned, the key is not added yet, add it at the last.
-  return {
-    ...currentState,
-    folderShortcuts: folderShortcuts.concat(key),
-  };
-}
-
-export function removeFolderShortcut(
-    currentState: State, action: RemoveFolderShortcutAction): State {
-  const {key} = action.payload;
-  const {folderShortcuts} = currentState;
-  const isExisted = folderShortcuts.find(k => k === key);
-  // Do nothing if the key is not existed.
-  if (!isExisted) {
-    return currentState;
-  }
-
-
-  return {
-    ...currentState,
-    folderShortcuts: folderShortcuts.filter(k => k !== key),
-  };
-}
diff --git a/ui/file_manager/file_manager/state/reducers/root.ts b/ui/file_manager/file_manager/state/reducers/root.ts
index 11a41218..be461819 100644
--- a/ui/file_manager/file_manager/state/reducers/root.ts
+++ b/ui/file_manager/file_manager/state/reducers/root.ts
@@ -4,15 +4,15 @@
 
 import {State} from '../../externs/ts/state.js';
 import {Action, ActionType} from '../actions.js';
+import {androidAppsReducersMap} from '../ducks/android_apps.js';
 import {bulkPinningReducersMap} from '../ducks/bulk_pinning.js';
+import {folderShortcutsReducersMap} from '../ducks/folder_shortcuts.js';
 import {searchReducersMap} from '../ducks/search.js';
 import {uiEntriesReducersMap} from '../ducks/ui_entries.js';
 import {volumesReducersMap} from '../ducks/volumes.js';
 
 import {addChildEntries, cacheEntries, clearCachedEntries, updateMetadata} from './all_entries.js';
-import {addAndroidApps} from './android_apps.js';
 import {changeDirectory, updateDirectoryContent, updateFileTasks, updateSelection} from './current_directory.js';
-import {addFolderShortcut, refreshFolderShortcut, removeFolderShortcut} from './folder_shortcuts.js';
 import {refreshNavigationRoots, updateNavigationEntry} from './navigation.js';
 import {updatePreferences} from './preferences.js';
 
@@ -22,6 +22,8 @@
   ...volumesReducersMap,
   ...bulkPinningReducersMap,
   ...uiEntriesReducersMap,
+  ...androidAppsReducersMap,
+  ...folderShortcutsReducersMap,
 ]);
 
 /**
@@ -60,14 +62,6 @@
       return refreshNavigationRoots(currentState, action);
     case ActionType.UPDATE_NAVIGATION_ENTRY:
       return updateNavigationEntry(currentState, action);
-    case ActionType.REFRESH_FOLDER_SHORTCUT:
-      return refreshFolderShortcut(currentState, action);
-    case ActionType.ADD_FOLDER_SHORTCUT:
-      return addFolderShortcut(currentState, action);
-    case ActionType.REMOVE_FOLDER_SHORTCUT:
-      return removeFolderShortcut(currentState, action);
-    case ActionType.ADD_ANDROID_APPS:
-      return addAndroidApps(currentState, action);
     case ActionType.ADD_CHILD_ENTRIES:
       return addChildEntries(currentState, action);
     case ActionType.UPDATE_PREFERENCES:
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni
index 4eacbe6..a2e05024 100644
--- a/ui/file_manager/file_names.gni
+++ b/ui/file_manager/file_names.gni
@@ -253,9 +253,7 @@
   # Actions.
   "file_manager/state/actions.ts",
   "file_manager/state/actions/all_entries.ts",
-  "file_manager/state/actions/android_apps.ts",
   "file_manager/state/actions/current_directory.ts",
-  "file_manager/state/actions/folder_shortcuts.ts",
   "file_manager/state/actions/navigation.ts",
   "file_manager/state/actions/preferences.ts",
 
@@ -266,18 +264,19 @@
   # Reducers.
   "file_manager/state/reducers/root.ts",
   "file_manager/state/reducers/all_entries.ts",
-  "file_manager/state/reducers/android_apps.ts",
   "file_manager/state/reducers/current_directory.ts",
-  "file_manager/state/reducers/folder_shortcuts.ts",
   "file_manager/state/reducers/navigation.ts",
   "file_manager/state/reducers/preferences.ts",
 
   # Ducks.
+  "file_manager/state/ducks/android_apps.ts",
   "file_manager/state/ducks/bulk_pinning.ts",
+  "file_manager/state/ducks/folder_shortcuts.ts",
   "file_manager/state/ducks/search.ts",
   "file_manager/state/ducks/ui_entries.ts",
   "file_manager/state/ducks/volumes.ts",
 
+
   # Containers.
   "file_manager/containers/breadcrumb_container.ts",
   "file_manager/containers/cloud_panel_container.ts",
@@ -400,17 +399,17 @@
   # Reducers:
   "file_manager/state/for_tests.ts",
   "file_manager/state/reducers/all_entries_unittest.ts",
-  "file_manager/state/reducers/android_apps_unittest.ts",
   "file_manager/state/reducers/current_directory_unittest.ts",
-  "file_manager/state/reducers/folder_shortcuts_unittest.ts",
   "file_manager/state/reducers/navigation_unittest.ts",
   "file_manager/state/reducers/preferences_unittest.ts",
 
   # Ducks:
+  "file_manager/state/ducks/android_apps_unittest.ts",
   "file_manager/state/ducks/bulk_pinning_unittest.ts",
+  "file_manager/state/ducks/folder_shortcuts_unittest.ts",
   "file_manager/state/ducks/search_unittest.ts",
-  "file_manager/state/ducks/volumes_unittest.ts",
   "file_manager/state/ducks/ui_entries_unittest.ts",
+  "file_manager/state/ducks/volumes_unittest.ts",
 
   # Widgets:
   "file_manager/widgets/xf_breadcrumb_unittest.ts",
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index b596c4a0d..96a5c7f 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -173,6 +173,9 @@
       behavior |= aura::client::kResizeBehaviorCanMaximize;
     if (delegate->CanMinimize())
       behavior |= aura::client::kResizeBehaviorCanMinimize;
+    if (delegate->CanFullscreen()) {
+      behavior |= aura::client::kResizeBehaviorCanFullscreen;
+    }
   }
   window->SetProperty(aura::client::kResizeBehaviorKey, behavior);
 }
diff --git a/ui/views/widget/native_widget_aura_unittest.cc b/ui/views/widget/native_widget_aura_unittest.cc
index 9c0ad27..f826ce0 100644
--- a/ui/views/widget/native_widget_aura_unittest.cc
+++ b/ui/views/widget/native_widget_aura_unittest.cc
@@ -445,7 +445,8 @@
   void OnWindowAddedToLayout(aura::Window* child) override {
     EXPECT_EQ(aura::client::kResizeBehaviorCanResize |
                   aura::client::kResizeBehaviorCanMaximize |
-                  aura::client::kResizeBehaviorCanMinimize,
+                  aura::client::kResizeBehaviorCanMinimize |
+                  aura::client::kResizeBehaviorCanFullscreen,
               child->GetProperty(aura::client::kResizeBehaviorKey));
     added_ = true;
   }
diff --git a/ui/views/widget/widget_delegate.cc b/ui/views/widget/widget_delegate.cc
index fcc5c347..59a17016 100644
--- a/ui/views/widget/widget_delegate.cc
+++ b/ui/views/widget/widget_delegate.cc
@@ -104,6 +104,10 @@
   return params_.can_minimize;
 }
 
+bool WidgetDelegate::CanFullscreen() const {
+  return params_.can_fullscreen;
+}
+
 bool WidgetDelegate::CanActivate() const {
   return can_activate_;
 }
@@ -375,8 +379,22 @@
   params_.accessible_title = std::move(title);
 }
 
+void WidgetDelegate::SetCanFullscreen(bool can_fullscreen) {
+  bool old_can_fullscreen =
+      std::exchange(params_.can_fullscreen, can_fullscreen);
+  if (GetWidget() && params_.can_fullscreen != old_can_fullscreen) {
+    GetWidget()->OnSizeConstraintsChanged();
+  }
+}
+
 void WidgetDelegate::SetCanMaximize(bool can_maximize) {
   bool old_can_maximize = std::exchange(params_.can_maximize, can_maximize);
+  // TODO(b/256551737): Remove this. CanMaximize currently means that a window
+  // is also able to go into fullscreen. We'd like to split the logic, but
+  // this could introduce some defects. Retaining current behaviour at the
+  // moment, then change it in another CL, so that it'll be easier to rollback
+  // in case there is a regression.
+  params_.can_fullscreen = true;
   if (GetWidget() && params_.can_maximize != old_can_maximize)
     GetWidget()->OnSizeConstraintsChanged();
 }
diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h
index 6982b27..6d87be8 100644
--- a/ui/views/widget/widget_delegate.h
+++ b/ui/views/widget/widget_delegate.h
@@ -55,7 +55,8 @@
     std::u16string accessible_title;
 
     // Whether the window should display controls for the user to minimize,
-    // maximize, or resize it.
+    // maximize, resize it, or go into fullscreen.
+    bool can_fullscreen = false;
     bool can_maximize = false;
     bool can_minimize = false;
     bool can_resize = false;
@@ -156,6 +157,9 @@
   // Returns true if the window can be resized.
   bool CanResize() const;
 
+  // Returns true if the window can go into fullscreen.
+  virtual bool CanFullscreen() const;
+
   // Returns true if the window can be maximized.
   virtual bool CanMaximize() const;
 
@@ -327,6 +331,7 @@
   // setters, there is no need to override the corresponding virtual getters.
   void SetAccessibleWindowRole(ax::mojom::Role role);
   void SetAccessibleTitle(std::u16string title);
+  void SetCanFullscreen(bool can_fullscreen);
   void SetCanMaximize(bool can_maximize);
   void SetCanMinimize(bool can_minimize);
   void SetCanResize(bool can_resize);
diff --git a/ui/views/widget/widget_delegate_unittest.cc b/ui/views/widget/widget_delegate_unittest.cc
index b4a9630..2e69b1c 100644
--- a/ui/views/widget/widget_delegate_unittest.cc
+++ b/ui/views/widget/widget_delegate_unittest.cc
@@ -15,6 +15,10 @@
 #include "ui/views/view.h"
 #include "ui/views/view_tracker.h"
 
+#if !BUILDFLAG(IS_APPLE)
+#include "ui/aura/client/aura_constants.h"
+#endif
+
 namespace views {
 namespace {
 
@@ -227,5 +231,31 @@
   widget.Close();
 }
 
+#if !BUILDFLAG(IS_APPLE)
+TEST_F(WidgetDelegateTest, SetCanFullscreen) {
+  TestWidgetDelegate delegate;
+  Widget widget;
+  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+  params.delegate = &delegate;
+  params.bounds = gfx::Rect(0, 0, 1024, 768);
+  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  widget.Init(std::move(params));
+
+  auto GetWidgetResizeBehavior = [&]() {
+    return widget.GetNativeWindow()->GetProperty(
+        aura::client::kResizeBehaviorKey);
+  };
+
+  EXPECT_FALSE(delegate.CanFullscreen());
+  EXPECT_FALSE(GetWidgetResizeBehavior() &
+               aura::client::kResizeBehaviorCanFullscreen);
+
+  delegate.SetCanFullscreen(true);
+  EXPECT_TRUE(delegate.CanFullscreen());
+  EXPECT_TRUE(GetWidgetResizeBehavior() &
+              aura::client::kResizeBehaviorCanFullscreen);
+}
+#endif
+
 }  // namespace
 }  // namespace views
diff --git a/ui/wm/core/window_util.cc b/ui/wm/core/window_util.cc
index 0b764e1..f7cab94e 100644
--- a/ui/wm/core/window_util.cc
+++ b/ui/wm/core/window_util.cc
@@ -141,6 +141,10 @@
   return window->GetProperty(aura::client::kShowStateKey) == state;
 }
 
+ui::WindowShowState GetWindowState(const aura::Window* window) {
+  return window->GetProperty(aura::client::kShowStateKey);
+}
+
 void SetWindowState(aura::Window* window, ui::WindowShowState state) {
   window->SetProperty(aura::client::kShowStateKey, state);
 }
diff --git a/ui/wm/core/window_util.h b/ui/wm/core/window_util.h
index 20bbade..dbbb6f16 100644
--- a/ui/wm/core/window_util.h
+++ b/ui/wm/core/window_util.h
@@ -40,6 +40,10 @@
 COMPONENT_EXPORT(UI_WM)
 bool WindowStateIs(const aura::Window* window, ui::WindowShowState state);
 
+// Returns |window|'s current show state.
+COMPONENT_EXPORT(UI_WM)
+ui::WindowShowState GetWindowState(const aura::Window* window);
+
 // Sets the window state to |state|.
 COMPONENT_EXPORT(UI_WM)
 void SetWindowState(aura::Window* window, ui::WindowShowState state);
diff --git a/weblayer/browser/stateful_ssl_host_state_delegate_factory.cc b/weblayer/browser/stateful_ssl_host_state_delegate_factory.cc
index ed38c75..5f905a220 100644
--- a/weblayer/browser/stateful_ssl_host_state_delegate_factory.cc
+++ b/weblayer/browser/stateful_ssl_host_state_delegate_factory.cc
@@ -38,9 +38,10 @@
 StatefulSSLHostStateDelegateFactory::~StatefulSSLHostStateDelegateFactory() =
     default;
 
-KeyedService* StatefulSSLHostStateDelegateFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+StatefulSSLHostStateDelegateFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* context) const {
-  return new StatefulSSLHostStateDelegate(
+  return std::make_unique<StatefulSSLHostStateDelegate>(
       context, user_prefs::UserPrefs::Get(context),
       HostContentSettingsMapFactory::GetForBrowserContext(context));
 }
diff --git a/weblayer/browser/stateful_ssl_host_state_delegate_factory.h b/weblayer/browser/stateful_ssl_host_state_delegate_factory.h
index 61e8982..37b7bba 100644
--- a/weblayer/browser/stateful_ssl_host_state_delegate_factory.h
+++ b/weblayer/browser/stateful_ssl_host_state_delegate_factory.h
@@ -35,7 +35,7 @@
       const StatefulSSLHostStateDelegateFactory&) = delete;
 
   // BrowserContextKeyedServiceFactory methods:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
diff --git a/weblayer/browser/translate_ranker_factory.cc b/weblayer/browser/translate_ranker_factory.cc
index 7392a5d..5935fb53 100644
--- a/weblayer/browser/translate_ranker_factory.cc
+++ b/weblayer/browser/translate_ranker_factory.cc
@@ -33,9 +33,10 @@
 
 TranslateRankerFactory::~TranslateRankerFactory() = default;
 
-KeyedService* TranslateRankerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+TranslateRankerFactory::BuildServiceInstanceForBrowserContext(
     content::BrowserContext* browser_context) const {
-  return new translate::TranslateRankerImpl(
+  return std::make_unique<translate::TranslateRankerImpl>(
       translate::TranslateRankerImpl::GetModelPath(browser_context->GetPath()),
       translate::TranslateRankerImpl::GetModelURL(), ukm::UkmRecorder::Get());
 }
diff --git a/weblayer/browser/translate_ranker_factory.h b/weblayer/browser/translate_ranker_factory.h
index d348c57..c3eebe3 100644
--- a/weblayer/browser/translate_ranker_factory.h
+++ b/weblayer/browser/translate_ranker_factory.h
@@ -36,7 +36,7 @@
   ~TranslateRankerFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
       content::BrowserContext* context) const override;
 
   // Note: In //chrome, when the service is requested for a