diff --git a/DEPS b/DEPS
index 1abd5b7..67206e0 100644
--- a/DEPS
+++ b/DEPS
@@ -245,15 +245,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '0e845dc8b05cb2d40d1c880184e33dd76081283a',
+  'skia_revision': '44c00ae64a4e3eb2ff815f3817e6f319d18c55cc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '6a99cab5c25fb3d5a0f61695f9561e461e8b045c',
+  'v8_revision': '1e1a53946af8b5dc3f724e8309659a37a1c9758f',
   # 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': '89467fa56406f2eb31ba176df5a97c144f82be24',
+  'angle_revision': 'cd157aae586cadf5445ebc54e71f94de9e34ac37',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -300,7 +300,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
-  'harfbuzz_revision': '77507a1d8d872d8cd4f62b807e933cd3e2cdb110',
+  'harfbuzz_revision': 'b8c2c1ab3778755a23ea449ba334959693388687',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Emoji Segmenter
   # and whatever else without interference from each other.
@@ -320,7 +320,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '5f9228ddb5d5253d35a94dca45253b0c93602108',
+  'devtools_frontend_revision': 'ba9ce69bea5495b2f948a1de8a56c59af2707310',
   # 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.
@@ -360,7 +360,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'ec9cf2a85c2a8266478182bae48f490d4e94c5fb',
+  'dawn_revision': 'fc2666486e0bba38114554059f9b4561c5b0c533',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -805,7 +805,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'yFvftcNOlZZJaFm5vRn6OVKPs5whEChqCg3ESP47ycIC',
+          'version': 'kbDXkyz0Cat6aywgnFl4onZ4E8LXiWFZPcSwBSi4ip4C',
       },
     ],
     'condition': 'checkout_android',
@@ -1024,7 +1024,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '1fc15953a44635ac693b455bdd9274e88f9dc301',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0bcf2265a78b0eb5034bd8d8bfa6eb3db482fa1f',
       'condition': 'checkout_chromeos',
   },
 
@@ -1612,7 +1612,7 @@
   'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@d891854a594a8c22bbe5fdea9cf89d93cd04d3e6',
 
   'src/third_party/vulkan_memory_allocator':
-    Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '5e49f57a6e71a026a54eb42e366de09a4142d24e',
+    Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
 
   # Display server protocol for Linux.
   'src/third_party/wayland/src': {
@@ -1648,7 +1648,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'fca7b339442bd70c5dc49bb33ee7f9466b560a97',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ba3893477163082d5f8573c59d1ce6729b330382',
+    Var('webrtc_git') + '/src.git' + '@' + '31bd9fadb690ae4664a78b24276252c4512d6205',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1718,7 +1718,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d0a254cdfc8bd083f11bb27312cee44041324900',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0d5929baa2a533e88c0937acfd1e58a81facde4e',
     'condition': 'checkout_src_internal',
   },
 
@@ -1748,7 +1748,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '3nCu8a_FU3cnomexOmxmf7_tyLV8iUyMFPYWuXgiHrsC',
+        'version': 'YOseUIB09TJa-n0y0G2xORAcV3n6KGyO9uhxXLPQHRAC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1759,7 +1759,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'g1FUIvTfX-NhpTsdAnv08anrQ4C79ky8d_IKuVOYK-UC',
+        'version': 'nxp-A809VoIxJs6enaEQ4p2-nkep-6PgZlYFlopdQRMC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 3705c3e..6bb157f 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -684,6 +684,15 @@
       [_THIRD_PARTY_EXCEPT_BLINK],  # Don't warn in third_party folders.
     ),
     (
+      r'\b(absl|std)::any\b',
+      (
+        'absl::any / std::any are not safe to use in a component build.'
+      ),
+      True,
+      # Not an error in third party folders, though it probably should be :)
+      [_THIRD_PARTY_EXCEPT_BLINK],
+    ),
+    (
       r'/\bstd::bind\b',
       (
         'std::bind is banned because of lifetime risks.',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 87fecd5..18108cb 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2117,6 +2117,7 @@
     "//components/soda:constants",
     "//components/strings",
     "//components/sync",
+    "//components/url_matcher",
     "//components/user_manager",
     "//components/vector_icons",
     "//components/viz/host",
@@ -2440,6 +2441,7 @@
     "rotator/screen_rotation_animation_unittest.cc",
     "rotator/screen_rotation_animator_unittest.cc",
     "screen_util_unittest.cc",
+    "session/fullscreen_controller_unittest.cc",
     "session/fullscreen_notification_bubble_unittest.cc",
     "session/session_controller_impl_unittest.cc",
     "shelf/assistant_overlay_unittest.cc",
diff --git a/ash/DEPS b/ash/DEPS
index 4fedb476..e1a683a 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -21,6 +21,7 @@
   "+components/strings",
   "+components/sync",
   "+components/ui_devtools",
+  "+components/url_matcher",
   "+components/vector_icons",
   "+components/viz/common",
   "+components/viz/host",
diff --git a/ash/app_list/app_list_presenter_impl_unittest.cc b/ash/app_list/app_list_presenter_impl_unittest.cc
index 3f7d232d..8e2512a 100644
--- a/ash/app_list/app_list_presenter_impl_unittest.cc
+++ b/ash/app_list/app_list_presenter_impl_unittest.cc
@@ -15,13 +15,19 @@
 #include "ash/app_list/views/app_list_item_view.h"
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/app_list/views/paged_apps_grid_view.h"
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
 #include "ui/aura/client/focus_client.h"
+#include "ui/aura/env.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_occlusion_tracker.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/display/display.h"
 #include "ui/events/test/event_generator.h"
@@ -36,7 +42,8 @@
 
 class AppListPresenterImplTest : public AshTestBase {
  public:
-  AppListPresenterImplTest() = default;
+  AppListPresenterImplTest()
+      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
 
   AppListPresenterImplTest(const AppListPresenterImplTest&) = delete;
   AppListPresenterImplTest& operator=(const AppListPresenterImplTest&) = delete;
@@ -47,6 +54,19 @@
     return Shell::Get()->app_list_controller()->fullscreen_presenter();
   }
 
+  // Enables tablet mode and fast-forwards mock time until window occlusion
+  // tracking is enabled. See TabletModeController::SuspendOcclusionTracker().
+  // This is necessary for AppListPresenterImpl::IsAtLeastPartiallyVisible() to
+  // return correct results.
+  void EnableTabletMode() {
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+    auto* occlusion_tracker =
+        aura::Env::GetInstance()->GetWindowOcclusionTracker();
+    while (occlusion_tracker->IsPaused()) {
+      task_environment()->FastForwardBy(base::Milliseconds(100));
+    }
+  }
+
   // Shows the app list on the primary display.
   void ShowAppList() {
     presenter()->Show(AppListViewState::kPeeking, GetPrimaryDisplay().id(),
@@ -63,8 +83,19 @@
   }
 };
 
+// Tests of clamshell mode. These can be deleted when ProductivityLauncher is
+// the default because AppListPresenterImpl will only be used for tablet mode.
+class AppListPresenterImplClamshellTest : public AppListPresenterImplTest {
+ public:
+  AppListPresenterImplClamshellTest() {
+    feature_list_.InitAndDisableFeature(features::kProductivityLauncher);
+  }
+
+  base::test::ScopedFeatureList feature_list_;
+};
+
 // Tests that app launcher is dismissed when focus moves to another window.
-TEST_F(AppListPresenterImplTest, HideOnFocusOut) {
+TEST_F(AppListPresenterImplClamshellTest, HideOnFocusOut) {
   // Show the app list and focus it.
   ShowAppList();
   aura::client::FocusClient* focus_client =
@@ -81,7 +112,7 @@
 }
 
 // Tests that the app list is dismissed when the app list's widget is destroyed.
-TEST_F(AppListPresenterImplTest, WidgetDestroyed) {
+TEST_F(AppListPresenterImplClamshellTest, WidgetDestroyed) {
   ShowAppList();
   EXPECT_TRUE(presenter()->GetTargetVisibility());
   presenter()->GetView()->GetWidget()->CloseNow();
@@ -89,7 +120,7 @@
 }
 
 // Test that clicking on app list context menus doesn't close the app list.
-TEST_F(AppListPresenterImplTest, ClickingContextMenuDoesNotDismiss) {
+TEST_F(AppListPresenterImplClamshellTest, ClickingContextMenuDoesNotDismiss) {
   // Populate some apps since we will show the context menu over a view.
   AppListModel* model = AppListModelProvider::Get()->model();
   model->AddItem(std::make_unique<AppListItem>("item 1"));
@@ -136,8 +167,9 @@
 TEST_F(AppListPresenterImplTest,
        ShelfBackgroundWithHomeLauncherAndContainerIdsShown) {
   // Enter tablet mode to display the home launcher.
-  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
-  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  EnableTabletMode();
+  ASSERT_TRUE(presenter()->GetTargetVisibility());
+  ASSERT_TRUE(presenter()->IsAtLeastPartiallyVisible());
   ShelfLayoutManager* shelf_layout_manager =
       Shelf::ForWindow(Shell::GetRootWindowForDisplayId(GetPrimaryDisplayId()))
           ->shelf_layout_manager();
@@ -151,7 +183,8 @@
     std::unique_ptr<views::Widget> widget = CreateTestWidget(nullptr, id);
 
     EXPECT_EQ(ShelfBackgroundType::kHomeLauncher,
-              shelf_layout_manager->GetShelfBackgroundType());
+              shelf_layout_manager->GetShelfBackgroundType())
+        << " container " << id;
     EXPECT_EQ(hotseat->state(), HotseatState::kShownHomeLauncher);
   }
 }
@@ -159,8 +192,7 @@
 // Tests that Assistant UI in tablet mode is closed when open another window.
 TEST_F(AppListPresenterImplTest, HideAssistantUIOnFocusOut) {
   // Enter tablet mode to display the home launcher.
-  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
-  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  EnableTabletMode();
   EXPECT_TRUE(presenter()->IsVisibleDeprecated());
   EXPECT_FALSE(IsShowingAssistantUI());
 
@@ -187,10 +219,8 @@
   // list presenter starts observing the shelf state.
   UpdateDisplay("600x400,600x400");
 
-  GetAppListTestHelper()->ShowAndRunLoop(GetSecondaryDisplay().id());
-
   // Enter tablet mode, so the test can trigger tablet mode exit later on.
-  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  EnableTabletMode();
 
   ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
diff --git a/ash/components/audio/audio_devices_pref_handler_impl.cc b/ash/components/audio/audio_devices_pref_handler_impl.cc
index 488f010..09659d8 100644
--- a/ash/components/audio/audio_devices_pref_handler_impl.cc
+++ b/ash/components/audio/audio_devices_pref_handler_impl.cc
@@ -139,7 +139,7 @@
   // Use this opportunity to remove input device record from
   // |device_volume_settings_|.
   // TODO(baileyberro): Remove this check in M94.
-  if (device_volume_settings_->HasKey(device_id)) {
+  if (device_volume_settings_->FindKey(device_id)) {
     device_volume_settings_->RemoveKey(device_id);
     SaveDevicesVolumePref();
   }
@@ -150,7 +150,7 @@
 
 bool AudioDevicesPrefHandlerImpl::GetMuteValue(const AudioDevice& device) {
   std::string device_id_str = GetDeviceIdString(device);
-  if (!device_mute_settings_->HasKey(device_id_str))
+  if (!device_mute_settings_->FindKey(device_id_str))
     MigrateDeviceMuteSettings(device_id_str, device);
 
   int mute =
@@ -175,9 +175,9 @@
                                                   bool active,
                                                   bool activate_by_user) {
   base::DictionaryValue dict;
-  dict.SetBoolean(kActiveKey, active);
+  dict.SetBoolKey(kActiveKey, active);
   if (active)
-    dict.SetBoolean(kActivateByUserKey, activate_by_user);
+    dict.SetBoolKey(kActivateByUserKey, activate_by_user);
 
   // Use this opportunity to remove device record under deprecated device ID,
   // if one exists.
@@ -193,7 +193,7 @@
                                                   bool* active,
                                                   bool* activate_by_user) {
   const std::string device_id_str = GetDeviceIdString(device);
-  if (!device_state_settings_->HasKey(device_id_str) &&
+  if (!device_state_settings_->FindKey(device_id_str) &&
       !MigrateDevicesStatePref(device_id_str, device)) {
     return false;
   }
@@ -245,7 +245,7 @@
     const AudioDevice& device) {
   DCHECK(!device.is_input);
   std::string device_id_str = GetDeviceIdString(device);
-  if (!device_volume_settings_->HasKey(device_id_str))
+  if (!device_volume_settings_->FindKey(device_id_str))
     MigrateDeviceVolumeGainSettings(device_id_str, device);
   return *device_volume_settings_->FindDoubleKey(device_id_str);
 }
@@ -254,7 +254,7 @@
     const AudioDevice& device) {
   DCHECK(device.is_input);
   std::string device_id_str = GetDeviceIdString(device);
-  if (!device_gain_settings_->HasKey(device_id_str))
+  if (!device_gain_settings_->FindKey(device_id_str))
     SetInputGainPrefValue(device, kDefaultInputGainPercent);
   return *device_gain_settings_->FindDoubleKey(device_id_str);
 }
diff --git a/ash/components/audio/audio_devices_pref_handler_impl_unittest.cc b/ash/components/audio/audio_devices_pref_handler_impl_unittest.cc
index d13b4f7..19b60d65 100644
--- a/ash/components/audio/audio_devices_pref_handler_impl_unittest.cc
+++ b/ash/components/audio/audio_devices_pref_handler_impl_unittest.cc
@@ -116,8 +116,8 @@
                                             prefs::kAudioDevicesState);
       base::DictionaryValue* pref = update.Get();
       base::DictionaryValue state;
-      state.SetBoolean("active", kPresetState.active);
-      state.SetBoolean("activate_by_user", kPresetState.activate_by_user);
+      state.SetBoolKey("active", kPresetState.active);
+      state.SetBoolKey("activate_by_user", kPresetState.activate_by_user);
       pref->SetPath(preset_key, std::move(state));
     }
 
diff --git a/ash/components/proximity_auth/screenlock_bridge.cc b/ash/components/proximity_auth/screenlock_bridge.cc
index dbd7ef85..fd8648cb 100644
--- a/ash/components/proximity_auth/screenlock_bridge.cc
+++ b/ash/components/proximity_auth/screenlock_bridge.cc
@@ -65,7 +65,7 @@
   if (!tooltip_.empty()) {
     base::DictionaryValue tooltip_options;
     tooltip_options.SetStringKey("text", tooltip_);
-    tooltip_options.SetBoolean("autoshow", autoshow_tooltip_);
+    tooltip_options.SetBoolKey("autoshow", autoshow_tooltip_);
     result->SetKey("tooltip", std::move(tooltip_options));
   }
 
@@ -73,7 +73,7 @@
     result->SetString("ariaLabel", aria_label_);
 
   if (hardlock_on_click_)
-    result->SetBoolean("hardlockOnClick", true);
+    result->SetBoolKey("hardlockOnClick", true);
 
   return result;
 }
diff --git a/ash/components/tether/wifi_hotspot_connector_unittest.cc b/ash/components/tether/wifi_hotspot_connector_unittest.cc
index 1160690..7c0768e 100644
--- a/ash/components/tether/wifi_hotspot_connector_unittest.cc
+++ b/ash/components/tether/wifi_hotspot_connector_unittest.cc
@@ -107,7 +107,8 @@
     void CreateConfiguration(base::DictionaryValue* shill_properties,
                              bool shared) override {
       EXPECT_FALSE(shared);
-      last_configuration_ = shill_properties->CreateDeepCopy();
+      last_configuration_ = base::DictionaryValue::From(
+          base::Value::ToUniquePtrValue(shill_properties->Clone()));
 
       // Prevent nested RunLoops when ConfigureServiceWithLastNetworkConfig()
       // calls NetworkStateTestHelper::ConfigureService(); that causes threading
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index eddf2c9..c6f66216d 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -624,6 +624,10 @@
 const base::Feature kFirmwareUpdaterApp = {"FirmwareUpdaterApp",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Controls whether to allow keeping full screen mode after unlock.
+const base::Feature kFullscreenAfterUnlockAllowed = {
+    "FullscreenAfterUnlockAllowed", base::FEATURE_ENABLED_BY_DEFAULT};
+
 // When enabled, there will be an alert bubble showing up when the device
 // returns from low brightness (e.g., sleep, closed cover) without a lock screen
 // and the active window is in fullscreen.
@@ -1161,11 +1165,6 @@
 const base::Feature kShowBluetoothDebugLogToggle{
     "ShowBluetoothDebugLogToggle", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Whether to show domain-related questionnaire in feedback report UI
-// (crbug/1241169).
-const base::Feature kShowFeedbackReportQuestionnaire{
-    "FeedbackReportQuestionnaire", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Shows the Play Store icon in Demo Mode.
 const base::Feature kShowPlayInDemoMode{"ShowPlayInDemoMode",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
@@ -1545,6 +1544,10 @@
   return base::FeatureList::IsEnabled(kFirmwareUpdaterApp);
 }
 
+bool IsFullscreenAfterUnlockAllowed() {
+  return base::FeatureList::IsEnabled(kFullscreenAfterUnlockAllowed);
+}
+
 bool IsFullscreenAlertBubbleEnabled() {
   return base::FeatureList::IsEnabled(kFullscreenAlertBubble);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index d3e06b57..cdba117 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -240,6 +240,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFiltersInRecents;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFirmwareUpdaterApp;
 COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kFullscreenAfterUnlockAllowed;
+COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kFullscreenAlertBubble;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFuseBox;
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -442,8 +444,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kShimlessRMAFlow;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kShowBluetoothDebugLogToggle;
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::Feature kShowFeedbackReportQuestionnaire;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kShowPlayInDemoMode;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kSmartDimExperimentalComponent;
@@ -559,6 +559,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFileManagerSwaEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFirmwareUpdaterAppEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFullscreenAfterUnlockAllowed();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFullscreenAlertBubbleEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGaiaCloseViewMessageEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGaiaReauthEndpointEnabled();
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc
index fb576b0..1a36981 100644
--- a/ash/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -475,12 +475,9 @@
                                         prefs::kSecondaryDisplays);
   base::DictionaryValue* pref_data = update.Get();
   base::Value layout_value(base::Value::Type::DICTIONARY);
-  if (pref_data->HasKey(name)) {
-    base::Value* value = nullptr;
-    if (pref_data->Get(name, &value) && value != nullptr) {
-      layout_value = value->Clone();
-    }
-  }
+  const base::Value* value = pref_data->FindKey(name);
+  if (value)
+    layout_value = value->Clone();
   if (display::DisplayLayoutToJson(display_layout, &layout_value))
     pref_data->SetPath(name, std::move(layout_value));
 }
@@ -569,7 +566,7 @@
           static_cast<int>(mode.device_scale_factor() * 1000));
 
       if (display::features::IsListAllDisplayModesEnabled()) {
-        property_value.SetBoolean("interlaced", mode.is_interlaced());
+        property_value.SetBoolKey("interlaced", mode.is_interlaced());
         property_value.SetDoubleKey("refresh-rate", mode.refresh_rate());
       }
     }
@@ -637,7 +634,7 @@
   DictionaryPrefUpdateDeprecated update(pref_service,
                                         prefs::kDisplayRotationLock);
   base::DictionaryValue* pref_data = update.Get();
-  pref_data->SetBoolean("lock", rotation_lock);
+  pref_data->SetBoolKey("lock", rotation_lock);
   pref_data->SetIntKey("orientation", static_cast<int>(rotation));
 }
 
diff --git a/ash/display/display_prefs_unittest.cc b/ash/display/display_prefs_unittest.cc
index bee4329..49a5cfeb 100644
--- a/ash/display/display_prefs_unittest.cc
+++ b/ash/display/display_prefs_unittest.cc
@@ -163,8 +163,8 @@
 
     base::DictionaryValue* pref_data = update.Get();
     base::Value layout_value(base::Value::Type::DICTIONARY);
-    base::Value* value = nullptr;
-    if (pref_data->Get(name, &value) && value != nullptr)
+    const base::Value* value = pref_data->FindKey(name);
+    if (value)
       layout_value = value->Clone();
     if (display::DisplayLayoutToJson(display_layout, &layout_value))
       pref_data->SetPath(name, std::move(layout_value));
@@ -185,7 +185,7 @@
                             base::Value::FromUniquePtrValue(std::move(value)));
     } else {
       base::DictionaryValue layout_value;
-      layout_value.SetBoolean(key, value != nullptr);
+      layout_value.SetBoolKey(key, value != nullptr);
       pref_data->SetPath(name, std::move(layout_value));
     }
   }
diff --git a/ash/public/cpp/shelf_prefs.cc b/ash/public/cpp/shelf_prefs.cc
index 1fd01913..f3becc8 100644
--- a/ash/public/cpp/shelf_prefs.cc
+++ b/ash/public/cpp/shelf_prefs.cc
@@ -108,12 +108,11 @@
 
   // TODO(crbug.com/1187061): Refactor this to remove base::DictionaryValue.
   DictionaryPrefUpdateDeprecated update(prefs, prefs::kShelfPreferences);
-  base::DictionaryValue* shelf_prefs = update.Get();
-  base::DictionaryValue* display_prefs_weak = nullptr;
-  if (!shelf_prefs->GetDictionary(display_key, &display_prefs_weak)) {
-    auto display_prefs = std::make_unique<base::DictionaryValue>();
-    display_prefs_weak = display_prefs.get();
-    shelf_prefs->Set(display_key, std::move(display_prefs));
+  base::Value* shelf_prefs = update.Get();
+  base::Value* display_prefs_weak = shelf_prefs->FindDictKey(display_key);
+  if (!display_prefs_weak) {
+    display_prefs_weak = shelf_prefs->SetKey(
+        display_key, base::Value(base::Value::Type::DICTIONARY));
   }
   display_prefs_weak->SetKey(pref_key, base::Value(value));
 }
diff --git a/ash/public/cpp/shelf_types.cc b/ash/public/cpp/shelf_types.cc
index ebfb50b..6fc11c2b 100644
--- a/ash/public/cpp/shelf_types.cc
+++ b/ash/public/cpp/shelf_types.cc
@@ -17,6 +17,31 @@
 
 }  // namespace
 
+std::ostream& operator<<(std::ostream& out, ShelfBackgroundType type) {
+  switch (type) {
+    case ShelfBackgroundType::kDefaultBg:
+      return out << "DefaultBg";
+    case ShelfBackgroundType::kMaximized:
+      return out << "Maximized";
+    case ShelfBackgroundType::kAppList:
+      return out << "AppList";
+    case ShelfBackgroundType::kHomeLauncher:
+      return out << "HomeLauncher";
+    case ShelfBackgroundType::kMaximizedWithAppList:
+      return out << "MaximizedWithAppList";
+    case ShelfBackgroundType::kOobe:
+      return out << "Oobe";
+    case ShelfBackgroundType::kLogin:
+      return out << "Login";
+    case ShelfBackgroundType::kLoginNonBlurredWallpaper:
+      return out << "LoginNonBlurredWallpaper";
+    case ShelfBackgroundType::kOverview:
+      return out << "Overview";
+    case ShelfBackgroundType::kInApp:
+      return out << "InApp";
+  }
+}
+
 bool IsValidShelfItemType(int64_t type) {
   switch (type) {
     case TYPE_PINNED_APP:
diff --git a/ash/public/cpp/shelf_types.h b/ash/public/cpp/shelf_types.h
index 1a524ad6..95ee1b4 100644
--- a/ash/public/cpp/shelf_types.h
+++ b/ash/public/cpp/shelf_types.h
@@ -6,6 +6,7 @@
 #define ASH_PUBLIC_CPP_SHELF_TYPES_H_
 
 #include <cstdint>
+#include <ostream>
 #include <string>
 
 #include "ash/public/cpp/ash_public_export.h"
@@ -106,6 +107,9 @@
   kInApp,
 };
 
+ASH_PUBLIC_EXPORT std::ostream& operator<<(std::ostream& out,
+                                           ShelfBackgroundType type);
+
 // Source of the launch or activation request, for tracking.
 enum ShelfLaunchSource {
   // The item was launched from an unknown source.
diff --git a/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc b/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc
index 9cd1d444..3619a19 100644
--- a/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc
+++ b/ash/quick_pair/common/fast_pair/fast_pair_metrics.cc
@@ -165,6 +165,10 @@
     "Bluetooth.ChromeOS.FastPair.PairDevice.Result";
 const char kPairDeviceErrorReason[] =
     "Bluetooth.ChromeOS.FastPair.PairDevice.ErrorReason";
+const char kConfirmPasskeyAskTime[] =
+    "Bluetooth.ChromeOS.FastPair.RequestPasskey.Latency";
+const char kConfirmPasskeyConfirmTime[] =
+    "Bluetooth.ChromeOS.FastPair.ConfirmPasskey.Latency";
 
 }  // namespace
 
@@ -464,5 +468,13 @@
       device::BluetoothDevice::NUM_CONNECT_ERROR_CODES);
 }
 
+void RecordConfirmPasskeyConfirmTime(base::TimeDelta total_confirm_time) {
+  base::UmaHistogramTimes(kConfirmPasskeyConfirmTime, total_confirm_time);
+}
+
+void RecordConfirmPasskeyAskTime(base::TimeDelta total_ask_time) {
+  base::UmaHistogramTimes(kConfirmPasskeyAskTime, total_ask_time);
+}
+
 }  // namespace quick_pair
 }  // namespace ash
diff --git a/ash/quick_pair/common/fast_pair/fast_pair_metrics.h b/ash/quick_pair/common/fast_pair/fast_pair_metrics.h
index b1c9e15..a9498ba4 100644
--- a/ash/quick_pair/common/fast_pair/fast_pair_metrics.h
+++ b/ash/quick_pair/common/fast_pair/fast_pair_metrics.h
@@ -214,7 +214,8 @@
 COMPONENT_EXPORT(QUICK_PAIR_COMMON)
 void RecordFastPairRepositoryCacheResult(bool success);
 
-COMPONENT_EXPORT(QUICK_PAIR_COMMON) void RecordHandshakeResult(bool success);
+COMPONENT_EXPORT(QUICK_PAIR_COMMON)
+void RecordHandshakeResult(bool success);
 
 COMPONENT_EXPORT(QUICK_PAIR_COMMON)
 void RecordHandshakeFailureReason(HandshakeFailureReason failure_reason);
@@ -245,6 +246,12 @@
 void RecordPairDeviceErrorReason(
     device::BluetoothDevice::ConnectErrorCode error_code);
 
+COMPONENT_EXPORT(QUICK_PAIR_COMMON)
+void RecordConfirmPasskeyConfirmTime(base::TimeDelta total_confirm_time);
+
+COMPONENT_EXPORT(QUICK_PAIR_COMMON)
+void RecordConfirmPasskeyAskTime(base::TimeDelta total_ask_time);
+
 }  // namespace quick_pair
 }  // namespace ash
 
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.cc b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.cc
index 8675258..1838153 100644
--- a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.cc
+++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.cc
@@ -202,10 +202,13 @@
     RecordPairDeviceErrorReason(error.value());
     return;
   }
+
+  ask_confirm_passkey_initial_time_ = base::TimeTicks::Now();
   QP_LOG(VERBOSE) << "Pair to device successful.";
 }
 
 void FastPairPairer::OnConnectDevice(device::BluetoothDevice* device) {
+  ask_confirm_passkey_initial_time_ = base::TimeTicks::Now();
   QP_LOG(VERBOSE) << "Connect device successful.";
   RecordConnectDeviceResult(/*success=*/true);
 }
@@ -219,6 +222,10 @@
 
 void FastPairPairer::ConfirmPasskey(device::BluetoothDevice* device,
                                     uint32_t passkey) {
+  RecordConfirmPasskeyAskTime(base::TimeTicks::Now() -
+                              ask_confirm_passkey_initial_time_);
+  confirm_passkey_initial_time_ = base::TimeTicks::Now();
+
   pairing_device_address_ = device->GetAddress();
   expected_passkey_ = passkey;
   fast_pair_gatt_service_client_->WritePasskeyAsync(
@@ -278,6 +285,8 @@
   RecordPasskeyCharacteristicDecryptResult(/*success=*/true);
   RecordPasskeyCharacteristicDecryptTime(base::TimeTicks::Now() -
                                          decrypt_start_time);
+  RecordConfirmPasskeyConfirmTime(base::TimeTicks::Now() -
+                                  confirm_passkey_initial_time_);
 
   device::BluetoothDevice* pairing_device =
       adapter_->GetDevice(pairing_device_address_);
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h
index 6e459f6..a6eec9bc 100644
--- a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h
+++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h
@@ -98,6 +98,10 @@
 
   void OnGattClientInitializedCallback(absl::optional<PairFailure> failure);
 
+  // Initial timestamps used for metrics.
+  base::TimeTicks ask_confirm_passkey_initial_time_;
+  base::TimeTicks confirm_passkey_initial_time_;
+
   uint32_t expected_passkey_;
   scoped_refptr<device::BluetoothAdapter> adapter_;
   scoped_refptr<Device> device_;
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_unittest.cc b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_unittest.cc
index 480ec396..ceb0381 100644
--- a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_unittest.cc
+++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_unittest.cc
@@ -82,6 +82,10 @@
     "Bluetooth.ChromeOS.FastPair.PairDevice.Result";
 const char kPairDeviceErrorReason[] =
     "Bluetooth.ChromeOS.FastPair.PairDevice.ErrorReason";
+const char kConfirmPasskeyAskTime[] =
+    "Bluetooth.ChromeOS.FastPair.RequestPasskey.Latency";
+const char kConfirmPasskeyConfirmTime[] =
+    "Bluetooth.ChromeOS.FastPair.ConfirmPasskey.Latency";
 
 class FakeBluetoothAdapter
     : public testing::NiceMock<device::MockBluetoothAdapter> {
@@ -693,6 +697,8 @@
 }
 
 TEST_F(FastPairPairerTest, PairSuccess_Initial) {
+  histogram_tester().ExpectTotalCount(kConfirmPasskeyAskTime, 0);
+  histogram_tester().ExpectTotalCount(kConfirmPasskeyConfirmTime, 0);
   histogram_tester().ExpectTotalCount(kPasskeyCharacteristicDecryptTime, 0);
   SuccessfulDataEncryptorSetUp(/*fast_pair_v1=*/false,
                                /*protocol=*/Protocol::kFastPairInitial);
@@ -711,9 +717,13 @@
   EXPECT_TRUE(IsDevicePaired());
   histogram_tester().ExpectTotalCount(kPasskeyCharacteristicDecryptTime, 1);
   histogram_tester().ExpectTotalCount(kPasskeyCharacteristicDecryptResult, 1);
+  histogram_tester().ExpectTotalCount(kConfirmPasskeyAskTime, 1);
+  histogram_tester().ExpectTotalCount(kConfirmPasskeyConfirmTime, 1);
 }
 
 TEST_F(FastPairPairerTest, PairSuccess_Subsequent) {
+  histogram_tester().ExpectTotalCount(kConfirmPasskeyAskTime, 0);
+  histogram_tester().ExpectTotalCount(kConfirmPasskeyConfirmTime, 0);
   histogram_tester().ExpectTotalCount(kPasskeyCharacteristicDecryptTime, 0);
   histogram_tester().ExpectTotalCount(kPasskeyCharacteristicDecryptResult, 0);
   SuccessfulDataEncryptorSetUp(/*fast_pair_v1=*/false,
@@ -733,6 +743,8 @@
   EXPECT_TRUE(IsDevicePaired());
   histogram_tester().ExpectTotalCount(kPasskeyCharacteristicDecryptTime, 1);
   histogram_tester().ExpectTotalCount(kPasskeyCharacteristicDecryptResult, 1);
+  histogram_tester().ExpectTotalCount(kConfirmPasskeyAskTime, 1);
+  histogram_tester().ExpectTotalCount(kConfirmPasskeyConfirmTime, 1);
 }
 
 TEST_F(FastPairPairerTest, WriteAccountKey_Initial) {
diff --git a/ash/services/nearby/public/mojom/BUILD.gn b/ash/services/nearby/public/mojom/BUILD.gn
index b1c83ac..c81f029 100644
--- a/ash/services/nearby/public/mojom/BUILD.gn
+++ b/ash/services/nearby/public/mojom/BUILD.gn
@@ -13,6 +13,7 @@
 
 mojom("mojom") {
   sources = [
+    "firewall_hole.mojom",
     "nearby_connections.mojom",
     "nearby_connections_types.mojom",
     "nearby_decoder.mojom",
diff --git a/ash/services/nearby/public/mojom/firewall_hole.mojom b/ash/services/nearby/public/mojom/firewall_hole.mojom
new file mode 100644
index 0000000..af0df39
--- /dev/null
+++ b/ash/services/nearby/public/mojom/firewall_hole.mojom
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module sharing.mojom;
+
+import "ash/services/nearby/public/mojom/tcp_server_socket_port.mojom";
+
+// Represents the firewall hole owned by the browser process. Consumer closes
+// the firewall hole by destroying the remote endpoint.
+interface FirewallHole {};
+
+// Opens a port in the Chrome OS system firewall. A firewall hole is necessary
+// for a TCP server socket to accept connections.
+interface FirewallHoleFactory {
+  // Opens a TCP firewall hole on |port|. The firewall hole's lifetime mirrors
+  // that of |firewall_hole|. Returns null on failure.
+  OpenFirewallHole(TcpServerSocketPort port)
+      => (pending_remote<FirewallHole>? firewall_hole);
+};
diff --git a/ash/session/fullscreen_controller.cc b/ash/session/fullscreen_controller.cc
index 9a2a57c..59f59a92 100644
--- a/ash/session/fullscreen_controller.cc
+++ b/ash/session/fullscreen_controller.cc
@@ -12,12 +12,15 @@
 #include "ash/session/session_controller_impl.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
+#include "ash/shell_delegate.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
 #include "chromeos/dbus/power_manager/backlight.pb.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "components/url_matcher/url_matcher.h"
+#include "components/url_matcher/url_util.h"
 
 namespace ash {
 
@@ -147,4 +150,34 @@
     MaybeShowNotification();
 }
 
+// static
+bool FullscreenController::ShouldExitFullscreenBeforeLock() {
+  // Check whether it is allowed to keep full screen on unlock.
+  if (!features::IsFullscreenAfterUnlockAllowed())
+    return true;
+
+  // Nothing to do if the active window is not in full screen mode.
+  WindowState* active_window_state = WindowState::ForActiveWindow();
+  if (!active_window_state || !active_window_state->IsFullscreen())
+    return false;
+
+  // Always exit full screen if the allowlist policy is unset.
+  auto* prefs = Shell::Get()->session_controller()->GetPrimaryUserPrefService();
+  const auto* url_allow_list =
+      prefs->GetList(prefs::kKeepFullscreenWithoutNotificationUrlAllowList);
+  if (url_allow_list->GetList().size() == 0)
+    return true;
+
+  // Get the URL of the active window from the shell delegate.
+  const GURL& url =
+      Shell::Get()->shell_delegate()->GetLastCommittedURLForWindowIfAny(
+          active_window_state->window());
+
+  // Check if it is allowed by user pref to keep full screen for the active URL.
+  url_matcher::URLMatcher url_matcher;
+  url_matcher::util::AddAllowFilters(
+      &url_matcher, &base::Value::AsListValue(*url_allow_list));
+  return url_matcher.MatchURL(url).empty();
+}
+
 }  // namespace ash
diff --git a/ash/session/fullscreen_controller.h b/ash/session/fullscreen_controller.h
index 9938b50..6c63761 100644
--- a/ash/session/fullscreen_controller.h
+++ b/ash/session/fullscreen_controller.h
@@ -29,6 +29,8 @@
 
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
+  static bool ShouldExitFullscreenBeforeLock();
+
  private:
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
diff --git a/ash/session/fullscreen_controller_unittest.cc b/ash/session/fullscreen_controller_unittest.cc
new file mode 100644
index 0000000..4294924
--- /dev/null
+++ b/ash/session/fullscreen_controller_unittest.cc
@@ -0,0 +1,181 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/session/fullscreen_controller.h"
+
+#include <memory>
+
+#include "ash/constants/ash_pref_names.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test_shell_delegate.h"
+#include "ash/wm/window_state.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+
+namespace ash {
+namespace {
+
+const GURL kActiveUrl = GURL("https://wwww.test.com");
+const GURL kEmptyUrl = GURL::EmptyGURL();
+
+constexpr char kNonMatchingPattern[] = "google.com";
+constexpr char kMatchingPattern[] = "test.com";
+constexpr char kWildcardPattern[] = "*";
+
+class FullscreenControllerTest : public AshTestBase {
+ public:
+  FullscreenControllerTest() {}
+
+  FullscreenControllerTest(const FullscreenControllerTest&) = delete;
+  FullscreenControllerTest& operator=(const FullscreenControllerTest&) = delete;
+
+  ~FullscreenControllerTest() override {}
+
+  // AshTestBase:
+  void SetUp() override {
+    // Create a shell delegate and set the active URL.
+    auto test_shell_delegate = std::make_unique<TestShellDelegate>();
+    test_shell_delegate_ = test_shell_delegate.get();
+    test_shell_delegate->SetLastCommittedURLForWindow(kActiveUrl);
+
+    AshTestBase::SetUp(std::move(test_shell_delegate));
+
+    CreateFullscreenWindow();
+  }
+
+  void TearDown() override {
+    window_.reset();
+    AshTestBase::TearDown();
+  }
+
+  void CreateFullscreenWindow() {
+    window_ = CreateTestWindow();
+    window_->SetProperty(aura::client::kShowStateKey,
+                         ui::SHOW_STATE_FULLSCREEN);
+    window_state_ = WindowState::Get(window_.get());
+  }
+
+  void SetKeepFullscreenWithoutNotificationAllowList(
+      const std::string& pattern) {
+    base::Value list(base::Value::Type::LIST);
+    list.Append(base::Value(pattern));
+    Shell::Get()->session_controller()->GetPrimaryUserPrefService()->Set(
+        prefs::kKeepFullscreenWithoutNotificationUrlAllowList, list);
+  }
+
+ protected:
+  std::unique_ptr<aura::Window> window_;
+
+  WindowState* window_state_ = nullptr;
+
+  raw_ptr<TestShellDelegate> test_shell_delegate_ = nullptr;
+};
+
+// Test that full screen is exited after session unlock if the allow list pref
+// is unset.
+TEST_F(FullscreenControllerTest, ExitFullscreenIfUnsetPref) {
+  EXPECT_TRUE(window_state_->IsFullscreen());
+
+  base::RunLoop run_loop;
+  Shell::Get()->session_controller()->PrepareForLock(run_loop.QuitClosure());
+  GetSessionControllerClient()->LockScreen();
+  GetSessionControllerClient()->UnlockScreen();
+  run_loop.Run();
+
+  EXPECT_FALSE(window_state_->IsFullscreen());
+}
+
+// Test that full screen is exited after session unlock if the URL of the active
+// window does not match any patterns from the allow list.
+TEST_F(FullscreenControllerTest, ExitFullscreenIfNonMatchingPref) {
+  SetKeepFullscreenWithoutNotificationAllowList(kNonMatchingPattern);
+
+  EXPECT_TRUE(window_state_->IsFullscreen());
+
+  base::RunLoop run_loop;
+  Shell::Get()->session_controller()->PrepareForLock(run_loop.QuitClosure());
+  GetSessionControllerClient()->LockScreen();
+  GetSessionControllerClient()->UnlockScreen();
+  run_loop.Run();
+
+  EXPECT_FALSE(window_state_->IsFullscreen());
+}
+
+// Test that full screen is not exited after session unlock if the URL of the
+// active window matches a pattern from the allow list.
+TEST_F(FullscreenControllerTest, KeepFullscreenIfMatchingPref) {
+  // Set up the URL exempt list with one matching and one non-matching pattern.
+  base::Value list(base::Value::Type::LIST);
+  list.Append(base::Value(kNonMatchingPattern));
+  list.Append(base::Value(kMatchingPattern));
+  Shell::Get()->session_controller()->GetPrimaryUserPrefService()->Set(
+      prefs::kKeepFullscreenWithoutNotificationUrlAllowList, list);
+
+  EXPECT_TRUE(window_state_->IsFullscreen());
+
+  base::RunLoop run_loop;
+  Shell::Get()->session_controller()->PrepareForLock(run_loop.QuitClosure());
+  GetSessionControllerClient()->LockScreen();
+  GetSessionControllerClient()->UnlockScreen();
+  run_loop.Run();
+
+  EXPECT_TRUE(window_state_->IsFullscreen());
+}
+
+// Test that full screen is not exited after session unlock if the allow list
+// includes the wildcard character.
+TEST_F(FullscreenControllerTest, KeepFullscreenIfWildcardPref) {
+  SetKeepFullscreenWithoutNotificationAllowList(kWildcardPattern);
+
+  EXPECT_TRUE(window_state_->IsFullscreen());
+
+  base::RunLoop run_loop;
+  Shell::Get()->session_controller()->PrepareForLock(run_loop.QuitClosure());
+  GetSessionControllerClient()->LockScreen();
+  GetSessionControllerClient()->UnlockScreen();
+  run_loop.Run();
+
+  EXPECT_TRUE(window_state_->IsFullscreen());
+}
+
+// Test that full screen is exited after session unlock if the URL is not
+// available.
+TEST_F(FullscreenControllerTest, ExitFullscreenIfUnsetUrlUnsetPref) {
+  test_shell_delegate_->SetLastCommittedURLForWindow(kEmptyUrl);
+
+  EXPECT_TRUE(window_state_->IsFullscreen());
+
+  base::RunLoop run_loop;
+  Shell::Get()->session_controller()->PrepareForLock(run_loop.QuitClosure());
+  GetSessionControllerClient()->LockScreen();
+  GetSessionControllerClient()->UnlockScreen();
+  run_loop.Run();
+
+  EXPECT_FALSE(window_state_->IsFullscreen());
+}
+
+// Test that full screen is not exited after session unlock if the allow list
+// includes the wildcard character and the URL is not available.
+TEST_F(FullscreenControllerTest, KeepFullscreenIfUnsetUrlWildcardPref) {
+  test_shell_delegate_->SetLastCommittedURLForWindow(kEmptyUrl);
+
+  SetKeepFullscreenWithoutNotificationAllowList(kWildcardPattern);
+
+  EXPECT_TRUE(window_state_->IsFullscreen());
+
+  base::RunLoop run_loop;
+  Shell::Get()->session_controller()->PrepareForLock(run_loop.QuitClosure());
+  GetSessionControllerClient()->LockScreen();
+  GetSessionControllerClient()->UnlockScreen();
+  run_loop.Run();
+
+  EXPECT_TRUE(window_state_->IsFullscreen());
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/session/session_controller_impl.cc b/ash/session/session_controller_impl.cc
index 3b05ebd..64fb272d 100644
--- a/ash/session/session_controller_impl.cc
+++ b/ash/session/session_controller_impl.cc
@@ -369,7 +369,9 @@
 }
 
 void SessionControllerImpl::PrepareForLock(PrepareForLockCallback callback) {
-  FullscreenController::MaybeExitFullscreen();
+  if (FullscreenController::ShouldExitFullscreenBeforeLock())
+    FullscreenController::MaybeExitFullscreen();
+
   std::move(callback).Run();
 }
 
diff --git a/ash/session/session_controller_impl_unittest.cc b/ash/session/session_controller_impl_unittest.cc
index 85a9b917..5a3c048 100644
--- a/ash/session/session_controller_impl_unittest.cc
+++ b/ash/session/session_controller_impl_unittest.cc
@@ -16,6 +16,7 @@
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/bind.h"
 #include "base/callback.h"
@@ -24,6 +25,7 @@
 #include "components/prefs/testing_pref_service.h"
 #include "components/user_manager/user_type.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
@@ -148,6 +150,49 @@
   TestSessionObserver observer_;
 };
 
+class SessionControllerImplWithShellTest : public AshTestBase {
+ public:
+  SessionControllerImplWithShellTest() = default;
+
+  SessionControllerImplWithShellTest(
+      const SessionControllerImplWithShellTest&) = delete;
+  SessionControllerImplWithShellTest& operator=(
+      const SessionControllerImplWithShellTest&) = delete;
+
+  ~SessionControllerImplWithShellTest() override = default;
+
+  // AshTestBase:
+  void SetUp() override {
+    AshTestBase::SetUp();
+    controller()->AddObserver(&observer_);
+  }
+
+  void TearDown() override {
+    controller()->RemoveObserver(&observer_);
+    window_.reset();
+    AshTestBase::TearDown();
+  }
+
+  void CreateFullscreenWindow() {
+    window_ = CreateTestWindow();
+    window_->SetProperty(aura::client::kShowStateKey,
+                         ui::SHOW_STATE_FULLSCREEN);
+    window_state_ = WindowState::Get(window_.get());
+  }
+
+  SessionControllerImpl* controller() {
+    return Shell::Get()->session_controller();
+  }
+  const TestSessionObserver* observer() const { return &observer_; }
+
+ protected:
+  WindowState* window_state_ = nullptr;
+
+ private:
+  TestSessionObserver observer_;
+  std::unique_ptr<aura::Window> window_;
+};
+
 // Tests that the simple session info is reflected properly.
 TEST_F(SessionControllerImplTest, SimpleSessionInfo) {
   SessionInfo info;
@@ -226,7 +271,7 @@
 }
 
 // Tests that session state can be set and reflected properly.
-TEST_F(SessionControllerImplTest, SessionState) {
+TEST_F(SessionControllerImplWithShellTest, SessionState) {
   const struct {
     SessionState state;
     bool expected_is_screen_locked;
@@ -244,7 +289,7 @@
   FillDefaultSessionInfo(&info);
   for (const auto& test_case : kTestCases) {
     info.state = test_case.state;
-    SetSessionInfo(info);
+    controller()->SetSessionInfo(info);
 
     EXPECT_EQ(test_case.state, controller()->GetSessionState())
         << "Test case state=" << static_cast<int>(test_case.state);
@@ -375,24 +420,21 @@
 // Tests that user session is unblocked with a running unlock animation so that
 // focus rules can find a correct activatable window after screen lock is
 // dismissed.
-TEST_F(SessionControllerImplTest,
+TEST_F(SessionControllerImplWithShellTest,
        UserSessionUnblockedWithRunningUnlockAnimation) {
   SessionInfo info;
   FillDefaultSessionInfo(&info);
 
   // LOCKED means blocked user session.
   info.state = SessionState::LOCKED;
-  SetSessionInfo(info);
+  controller()->SetSessionInfo(info);
   EXPECT_TRUE(controller()->IsUserSessionBlocked());
 
-  // Mark a running unlock animation unblocks user session.
-  controller()->RunUnlockAnimation(base::OnceClosure());
-  EXPECT_FALSE(controller()->IsUserSessionBlocked());
-
   const struct {
     SessionState state;
-    bool expected_is_user_session_blocked;
+    bool expect_blocked_after_unlock_animation;
   } kTestCases[] = {
+      {SessionState::LOCKED, false},
       {SessionState::OOBE, true},
       {SessionState::LOGIN_PRIMARY, true},
       {SessionState::LOGGED_IN_NOT_ACTIVE, false},
@@ -401,12 +443,13 @@
   };
   for (const auto& test_case : kTestCases) {
     info.state = test_case.state;
-    SetSessionInfo(info);
+    controller()->SetSessionInfo(info);
 
     // Mark a running unlock animation.
-    controller()->RunUnlockAnimation(base::OnceClosure());
-
-    EXPECT_EQ(test_case.expected_is_user_session_blocked,
+    base::RunLoop run_loop;
+    controller()->RunUnlockAnimation(run_loop.QuitClosure());
+    run_loop.Run();
+    EXPECT_EQ(test_case.expect_blocked_after_unlock_animation,
               controller()->IsUserSessionBlocked())
         << "Test case state=" << static_cast<int>(test_case.state);
   }
@@ -798,5 +841,15 @@
   EXPECT_TRUE(widget->IsActive());
 }
 
+TEST_F(SessionControllerImplWithShellTest, ExitFullscreenBeforeLock) {
+  CreateFullscreenWindow();
+  EXPECT_TRUE(window_state_->IsFullscreen());
+
+  base::RunLoop run_loop;
+  Shell::Get()->session_controller()->PrepareForLock(run_loop.QuitClosure());
+
+  EXPECT_FALSE(window_state_->IsFullscreen());
+}
+
 }  // namespace
 }  // namespace ash
diff --git a/ash/shell_delegate.cc b/ash/shell_delegate.cc
index 9d627cc..48cd1a31 100644
--- a/ash/shell_delegate.cc
+++ b/ash/shell_delegate.cc
@@ -30,4 +30,9 @@
   return -1;
 }
 
+const GURL& ShellDelegate::GetLastCommittedURLForWindowIfAny(
+    aura::Window* window) {
+  return GURL::EmptyGURL();
+}
+
 }  // namespace ash
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index df02db1..50300954 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -17,6 +17,7 @@
 #include "services/device/public/mojom/fingerprint.mojom-forward.h"
 #include "services/media_session/public/cpp/media_session_service.h"
 #include "ui/gfx/native_widget_types.h"
+#include "url/gurl.h"
 
 namespace aura {
 class Window;
@@ -129,6 +130,10 @@
   // persistent desks bar. Note, this will be removed once the feature is fully
   // launched or removed.
   virtual void OpenFeedbackPageForPersistentDesksBar() = 0;
+
+  // Returns the last committed URL from the web contents if the given |window|
+  // contains a browser frame, otherwise returns GURL::EmptyURL().
+  virtual const GURL& GetLastCommittedURLForWindowIfAny(aura::Window* window);
 };
 
 }  // namespace ash
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index 3a5a2ed..6f9b5c54 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -13,6 +13,7 @@
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/wm/gestures/back_gesture/test_back_gesture_contextual_nudge_delegate.h"
 #include "ui/gfx/image/image.h"
+#include "url/gurl.h"
 
 namespace ash {
 
@@ -98,4 +99,13 @@
   return base::FilePath();
 }
 
+const GURL& TestShellDelegate::GetLastCommittedURLForWindowIfAny(
+    aura::Window* window) {
+  return last_committed_url_;
+}
+
+void TestShellDelegate::SetLastCommittedURLForWindow(const GURL& url) {
+  last_committed_url_ = url;
+}
+
 }  // namespace ash
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index cc2c940..81713df 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "url/gurl.h"
 
 namespace ash {
 
@@ -54,6 +55,7 @@
       override;
   bool IsSessionRestoreInProgress() const override;
   void SetUpEnvironmentForLockedFullscreen(bool locked) override {}
+  const GURL& GetLastCommittedURLForWindowIfAny(aura::Window* window) override;
 
   void SetCanGoBack(bool can_go_back);
   void SetShouldWaitForTouchAck(bool should_wait_for_touch_ack);
@@ -61,6 +63,7 @@
   bool IsLoggingRedirectDisabled() const override;
   base::FilePath GetPrimaryUserDownloadsFolder() const override;
   void OpenFeedbackPageForPersistentDesksBar() override {}
+  void SetLastCommittedURLForWindow(const GURL& url);
 
  private:
   // True if the current top window can go back.
@@ -79,6 +82,8 @@
   bool session_restore_in_progress_ = false;
 
   MultiDeviceSetupBinder multidevice_setup_binder_;
+
+  GURL last_committed_url_ = GURL::EmptyGURL();
 };
 
 }  // namespace ash
diff --git a/ash/webui/eche_app_ui/system_info_provider.cc b/ash/webui/eche_app_ui/system_info_provider.cc
index eba44de2..c687558 100644
--- a/ash/webui/eche_app_ui/system_info_provider.cc
+++ b/ash/webui/eche_app_ui/system_info_provider.cc
@@ -66,14 +66,14 @@
   json_dictionary.SetStringKey(kJsonDeviceNameKey,
                                system_info_->GetDeviceName());
   json_dictionary.SetStringKey(kJsonBoardNameKey, system_info_->GetBoardName());
-  json_dictionary.SetBoolean(kJsonTabletModeKey,
+  json_dictionary.SetBoolKey(kJsonTabletModeKey,
                              TabletMode::Get()->InTabletMode());
   auto found_type = CONNECTION_STATE_TYPE.find(wifi_connection_state_);
   std::string connecton_state_string =
       found_type == CONNECTION_STATE_TYPE.end() ? "" : found_type->second;
   json_dictionary.SetStringKey(kJsonWifiConnectionStateKey,
                                connecton_state_string);
-  json_dictionary.SetBoolean(
+  json_dictionary.SetBoolKey(
       kJsonDebugModeKey,
       base::FeatureList::IsEnabled(features::kEcheSWADebugMode));
 
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_controller.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_controller.ts
index 4fccdc8..fb1abfc 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_controller.ts
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_controller.ts
@@ -239,11 +239,6 @@
   store.endBatchUpdate();
 }
 
-/**
- * @param {!WallpaperLayout} layout
- * @param {!WallpaperProviderInterface} provider
- * @param {!PersonalizationStore} store
- */
 export async function setCustomWallpaperLayout(
     layout: WallpaperLayout, provider: WallpaperProviderInterface,
     store: PersonalizationStore): Promise<void> {
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_interface_provider.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_interface_provider.ts
index c5dfb6a..0d6d799 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_interface_provider.ts
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_interface_provider.ts
@@ -15,10 +15,6 @@
 
 let wallpaperProvider: WallpaperProviderInterface|null = null;
 
-/**
- * @param {!WallpaperProviderInterface}
- *     testProvider
- */
 export function setWallpaperProviderForTesting(
     testProvider: WallpaperProviderInterface): void {
   wallpaperProvider = testProvider;
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_preview_element.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_preview_element.ts
index 4a692cae..97e7c41e 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_preview_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_preview_element.ts
@@ -22,10 +22,6 @@
 
 import {getWallpaperProvider} from './wallpaper_interface_provider.js';
 
-/**
- * @polymer
- * @implements WallpaperObserverInterface
- */
 export class WallpaperPreview extends WithPersonalizationStore {
   static get is() {
     return 'wallpaper-preview';
@@ -57,11 +53,9 @@
 
   constructor() {
     super();
-    /** @private */
     this.wallpaperProvider_ = getWallpaperProvider();
   }
 
-  /** @override */
   connectedCallback() {
     super.connectedCallback();
     this.watch('image_', state => state.wallpaper.currentSelected);
@@ -76,7 +70,7 @@
   /**
    * Reload at the wallpaper collections page.
    */
-  onClickWallpaper_() {
+  private onClickWallpaper_() {
     PersonalizationRouter.reloadAtWallpaper();
   }
 
@@ -84,7 +78,7 @@
    * Return a chrome://image or data:// url to load the image safely. Returns
    * empty string in case |image| is null or invalid.
    */
-  getImageSrc_(image: CurrentWallpaper|null): string {
+  private getImageSrc_(image: CurrentWallpaper|null): string {
     if (image && image.url) {
       if (hasHttpScheme(image.url.url)) {
         return `chrome://image?${removeHighResolutionSuffix(image.url.url)}`;
@@ -94,7 +88,8 @@
     return '';
   }
 
-  computeShowImage_(image: CurrentWallpaper|null, loading: boolean): boolean {
+  private computeShowImage_(image: CurrentWallpaper|null, loading: boolean):
+      boolean {
     // Specifically check === false to avoid undefined case while component is
     // initializing.
     return loading === false && !!image;
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_reducers.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_reducers.ts
index 841793fb..9512b333 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_reducers.ts
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/wallpaper_reducers.ts
@@ -278,7 +278,7 @@
       }
       return state;
     case WallpaperActionName.SET_FULLSCREEN_ENABLED:
-      if (!(/** @type {{enabled: boolean}} */ (action)).enabled) {
+      if (!action.enabled) {
         // Clear the pending selected state after full screen is dismissed.
         return null;
       }
diff --git a/ash/webui/personalization_app/resources/untrusted/collections.html b/ash/webui/personalization_app/resources/untrusted/collections.html
index 2326502..02d6463 100644
--- a/ash/webui/personalization_app/resources/untrusted/collections.html
+++ b/ash/webui/personalization_app/resources/untrusted/collections.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="utf-8">
   <link rel="stylesheet" href="/common/base.css">
-  <link rel="stylesheet" href="/chromeos/colors/cros_styles.css">
+  <link rel="stylesheet" href="//resources/chromeos/colors/cros_styles.css">
   <script type="module" src="collections_grid.js" defer></script>
 </head>
 <body>
diff --git a/ash/webui/personalization_app/resources/untrusted/images.html b/ash/webui/personalization_app/resources/untrusted/images.html
index ce40fe30..2a3368f3 100644
--- a/ash/webui/personalization_app/resources/untrusted/images.html
+++ b/ash/webui/personalization_app/resources/untrusted/images.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="utf-8">
   <link rel="stylesheet" href="/common/base.css">
-  <link rel="stylesheet" href="/chromeos/colors/cros_styles.css">
+  <link rel="stylesheet" href="//resources/chromeos/colors/cros_styles.css">
   <script type="module" src="images_grid.js" defer></script>
 </head>
 <body>
diff --git a/ash/webui/personalization_app/untrusted_personalization_app_ui_config.cc b/ash/webui/personalization_app/untrusted_personalization_app_ui_config.cc
index 07c10773..d6877e2 100644
--- a/ash/webui/personalization_app/untrusted_personalization_app_ui_config.cc
+++ b/ash/webui/personalization_app/untrusted_personalization_app_ui_config.cc
@@ -77,7 +77,7 @@
 
     source->OverrideContentSecurityPolicy(
         network::mojom::CSPDirectiveName::StyleSrc,
-        "style-src 'self' 'unsafe-inline';");
+        "style-src 'self' 'unsafe-inline' chrome-untrusted://resources;");
 
 #if !DCHECK_IS_ON()
     // When DCHECKs are off and a user goes to an invalid url serve a default
diff --git a/ash/webui/shimless_rma/resources/calibration_component_chip.html b/ash/webui/shimless_rma/resources/calibration_component_chip.html
index 3e4a5fc..17e686cf 100644
--- a/ash/webui/shimless_rma/resources/calibration_component_chip.html
+++ b/ash/webui/shimless_rma/resources/calibration_component_chip.html
@@ -40,7 +40,8 @@
   }
 </style>
 
-<cr-button id="componentButton" on-click="onComponentButtonClicked_">
+<cr-button id="componentButton" on-click="onComponentButtonClicked_"
+    disabled="[[disabled]]">
   <div id="labelDiv">
     <iron-icon id="infoIcon" icon="shimless-icon:info" hidden="[[!failed]]">
     </iron-icon>
diff --git a/ash/webui/shimless_rma/resources/calibration_component_chip.js b/ash/webui/shimless_rma/resources/calibration_component_chip.js
index 547025b..62d71e7c 100644
--- a/ash/webui/shimless_rma/resources/calibration_component_chip.js
+++ b/ash/webui/shimless_rma/resources/calibration_component_chip.js
@@ -42,6 +42,12 @@
 
       /** @type {string} */
       componentName: {type: String, value: ''},
+
+      /** @type {boolean} */
+      disabled: {
+        type: Boolean,
+        value: false,
+      },
     };
   }
 
diff --git a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.html b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.html
index b56c342..b0a96887 100644
--- a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.html
+++ b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.html
@@ -7,7 +7,8 @@
     <div>[[i18n('calibrationFailedInstructionsText')]]</div>
     <div>
       <cr-button id="retryCalibrationButton" class="cancel-button"
-          on-click="onRetryCalibrationButtonClicked_">
+          on-click="onRetryCalibrationButtonClicked_"
+          disabled="[[allButtonsDisabled]]">
         [[i18n('calibrationFailedRetryButtonLabel')]]
       </cr-button>
     </div>
@@ -18,7 +19,8 @@
         <calibration-component-chip id="[[component.id]]"
           checked="{{component.checked}}"
           failed="[[component.failed]]"
-          component-name="[[component.name]]">
+          component-name="[[component.name]]"
+          disabled="[[allButtonsDisabled]]">
         </calibration-component-chip>
       </template>
     </div>
diff --git a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js
index 333012284..22e968751 100644
--- a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js
+++ b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js
@@ -58,6 +58,12 @@
 
   static get properties() {
     return {
+      /**
+       * Set by shimless_rma.js.
+       * @type {boolean}
+       */
+      allButtonsDisabled: Boolean,
+
       /** @private {!Array<!ComponentCheckbox>} */
       componentCheckboxes_: {
         type: Array,
diff --git a/ash/webui/shimless_rma/resources/reimaging_device_information_page.html b/ash/webui/shimless_rma/resources/reimaging_device_information_page.html
index dddc93a..a2e92f1 100644
--- a/ash/webui/shimless_rma/resources/reimaging_device_information_page.html
+++ b/ash/webui/shimless_rma/resources/reimaging_device_information_page.html
@@ -65,7 +65,8 @@
             placeholder=
                 "[[i18n('confirmDeviceInfoDramPartNumberPlaceholderLabel')]]"
             value="{{dramPartNumber_}}"
-            aria-labelledby="dramPartNumberLabel">
+            aria-labelledby="dramPartNumberLabel"
+            disabled="[[allButtonsDisabled]]">
         </cr-input>
         <cr-button id="resetDramPartNumber"
             on-click="onResetDramPartNumberButtonClicked_"
@@ -99,8 +100,9 @@
         [[i18n('confirmDeviceInfoWhiteLabelLabel')]]
       </label>
       <div class="input-holder">
-        <select id="whiteLabelSelect" class="md-select"
-            on-change="onSelectedWhiteLabelChange_" aria-labelledby="whiteLabelLabel">
+        <select id="whiteLabelSelect" class="md-select" 
+            on-change="onSelectedWhiteLabelChange_"
+            aria-labelledby="whiteLabelLabel" disabled="[[allButtonsDisabled]]">
           <template is="dom-repeat" items="[[whiteLabels_]]" as="whiteLabel">
             <option value="[[whiteLabel]]">
               [[whiteLabel]]
diff --git a/ash/webui/shimless_rma/resources/reimaging_device_information_page.js b/ash/webui/shimless_rma/resources/reimaging_device_information_page.js
index d5bd4aaf..b182db36 100644
--- a/ash/webui/shimless_rma/resources/reimaging_device_information_page.js
+++ b/ash/webui/shimless_rma/resources/reimaging_device_information_page.js
@@ -79,14 +79,14 @@
       disableResetWhiteLabel_: {
         type: Boolean,
         computed: 'getDisableResetWhiteLabel_(' +
-            'originalWhiteLabelIndex_, whiteLabelIndex_)',
+            'originalWhiteLabelIndex_, whiteLabelIndex_, allButtonsDisabled)',
       },
 
       /** @protected */
       disableResetDramPartNumber_: {
         type: Boolean,
         computed: 'getDisableResetDramPartNumber_(' +
-            'originalDramPartNumber_, dramPartNumber_)',
+            'originalDramPartNumber_, dramPartNumber_, allButtonsDisabled)',
       },
 
       /** @protected */
@@ -303,12 +303,14 @@
 
   /** @protected */
   getDisableResetWhiteLabel_() {
-    return this.originalWhiteLabelIndex_ === this.whiteLabelIndex_;
+    return this.originalWhiteLabelIndex_ === this.whiteLabelIndex_ ||
+        this.allButtonsDisabled;
   }
 
   /** @protected */
   getDisableResetDramPartNumber_() {
-    return this.originalDramPartNumber_ === this.dramPartNumber_;
+    return this.originalDramPartNumber_ === this.dramPartNumber_ ||
+        this.allButtonsDisabled;
   }
 
   /** @protected */
diff --git a/ash/wm/desks/desks_restore_util.cc b/ash/wm/desks/desks_restore_util.cc
index 9a9a863e..e4142ef 100644
--- a/ash/wm/desks/desks_restore_util.cc
+++ b/ash/wm/desks/desks_restore_util.cc
@@ -308,7 +308,7 @@
         desk->creation_time().ToDeltaSinceWindowsEpoch().InMinutes());
     metrics_dict.SetIntKey(kFirstDayVisitedKey, desk->first_day_visited());
     metrics_dict.SetIntKey(kLastDayVisitedKey, desk->last_day_visited());
-    metrics_dict.SetBoolean(kInteractedWithThisWeekKey,
+    metrics_dict.SetBoolKey(kInteractedWithThisWeekKey,
                             desk->interacted_with_this_week());
     metrics_pref_data->Append(std::move(metrics_dict));
   }
diff --git a/ash/wm/desks/templates/desks_templates_test_util.cc b/ash/wm/desks/templates/desks_templates_test_util.cc
index ac13949e..bb46796 100644
--- a/ash/wm/desks/templates/desks_templates_test_util.cc
+++ b/ash/wm/desks/templates/desks_templates_test_util.cc
@@ -131,8 +131,7 @@
   const auto* overview_grid = GetPrimaryOverviewGrid();
   if (!overview_grid)
     return nullptr;
-  views::Widget* widget =
-      overview_grid->save_desk_as_template_widget_for_testing();
+  views::Widget* widget = overview_grid->save_desk_as_template_widget();
   return widget ? static_cast<views::Button*>(widget->GetContentsView())
                 : nullptr;
 }
diff --git a/ash/wm/desks/templates/desks_templates_unittest.cc b/ash/wm/desks/templates/desks_templates_unittest.cc
index 989381d1..3f0a4fd8 100644
--- a/ash/wm/desks/templates/desks_templates_unittest.cc
+++ b/ash/wm/desks/templates/desks_templates_unittest.cc
@@ -32,6 +32,7 @@
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/overview_grid.h"
 #include "ash/wm/overview/overview_highlight_controller.h"
+#include "ash/wm/overview/overview_item.h"
 #include "ash/wm/overview/overview_session.h"
 #include "ash/wm/overview/overview_test_base.h"
 #include "ash/wm/overview/overview_test_util.h"
@@ -2075,4 +2076,33 @@
   histogram_tester.ExpectBucketCount(kWindowAndTabCountHistogramName, 6, 1);
 }
 
+// Tests that accessibility overrides are set as expected.
+TEST_F(DesksTemplatesTest, AccessibilityFocusAnnotatorInOverview) {
+  auto window = CreateTestWindow(gfx::Rect(100, 100));
+
+  ToggleOverview();
+  WaitForDesksTemplatesUI();
+
+  auto* focus_widget = views::Widget::GetWidgetForNativeWindow(
+      GetOverviewSession()->GetOverviewFocusWindow());
+  DCHECK(focus_widget);
+
+  OverviewGrid* grid = GetOverviewSession()->grid_list()[0].get();
+  auto* desk_widget = const_cast<views::Widget*>(grid->desks_widget());
+  DCHECK(desk_widget);
+
+  auto* save_widget =
+      GetSaveDeskAsTemplateButtonForRoot(Shell::GetPrimaryRootWindow());
+
+  // Overview items are in MRU order, so the expected order in the grid list is
+  // the reverse creation order.
+  auto* item_widget = GetOverviewItemForWindow(window.get())->item_widget();
+
+  // Order should be [focus_widget, save_widget, item_widget, desk_widget].
+  CheckA11yOverrides("focus", focus_widget, desk_widget, save_widget);
+  CheckA11yOverrides("save", save_widget, focus_widget, item_widget);
+  CheckA11yOverrides("item", item_widget, save_widget, desk_widget);
+  CheckA11yOverrides("desk", desk_widget, item_widget, focus_widget);
+}
+
 }  // namespace ash
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 470ef93..ddaf6175 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -1825,19 +1825,22 @@
   // Do not create or show the save desk as template button if there are no
   // windows in this grid, during a window drag or in tablet mode, or the desks
   // templates grid is visible.
-  const bool visible =
+  const bool target_visible =
       !window_list_.empty() &&
       !overview_session_->GetCurrentDraggedOverviewItem() &&
       !Shell::Get()->tablet_mode_controller()->InTabletMode() &&
       !IsShowingDesksTemplatesGrid();
+  if (target_visible == IsSaveDeskAsTemplateButtonVisible())
+    return;
 
-  if (!visible) {
+  if (!target_visible) {
     if (save_desk_as_template_widget_) {
       PerformFadeOutLayer(
           save_desk_as_template_widget_->GetLayer(),
           base::BindOnce(&OverviewGrid::OnSaveDeskAsTemplateButtonFadedOut,
                          weak_ptr_factory_.GetWeakPtr()));
     }
+    overview_session_->UpdateAccessibilityFocus();
     return;
   }
 
@@ -1845,7 +1848,7 @@
     save_desk_as_template_widget_ = SaveDeskAsTemplateWidget(root_window_);
     save_desk_as_template_widget_->SetContentsView(std::make_unique<PillButton>(
         base::BindRepeating(&OverviewGrid::OnSaveDeskAsTemplateButtonPressed,
-                            base::Unretained(this)),
+                            weak_ptr_factory_.GetWeakPtr()),
         l10n_util::GetStringUTF16(
             IDS_ASH_DESKS_TEMPLATES_SAVE_DESK_AS_TEMPLATE_BUTTON),
         PillButton::Type::kIcon, &kSaveDeskAsTemplateIcon));
@@ -1874,6 +1877,16 @@
       overview_item_bounds.x(),
       overview_item_bounds.y() - kSaveDeskAsTemplateOverviewItemSpacingDp,
       preferred_size.width(), preferred_size.height()));
+
+  overview_session_->UpdateAccessibilityFocus();
+}
+
+bool OverviewGrid::IsSaveDeskAsTemplateButtonVisible() const {
+  // The widget may be visible but in the process of fading away. We treat that
+  // as not visible.
+  return save_desk_as_template_widget_ &&
+         save_desk_as_template_widget_->IsVisible() &&
+         save_desk_as_template_widget_->GetLayer()->GetTargetOpacity() == 1.f;
 }
 
 void OverviewGrid::OnSplitViewStateChanged(
diff --git a/ash/wm/overview/overview_grid.h b/ash/wm/overview/overview_grid.h
index f85d611f..1baba27 100644
--- a/ash/wm/overview/overview_grid.h
+++ b/ash/wm/overview/overview_grid.h
@@ -361,6 +361,8 @@
   // button if it hasn't been created already, else it just sets its bounds.
   void UpdateSaveDeskAsTemplateButton();
 
+  bool IsSaveDeskAsTemplateButtonVisible() const;
+
   // SplitViewObserver:
   void OnSplitViewStateChanged(SplitViewController::State previous_state,
                                SplitViewController::State state) override;
@@ -420,7 +422,7 @@
     return desks_templates_grid_widget_.get();
   }
 
-  views::Widget* save_desk_as_template_widget_for_testing() const {
+  views::Widget* save_desk_as_template_widget() const {
     return save_desk_as_template_widget_.get();
   }
 
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index 918043b..4fb8c5a 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -1012,6 +1012,62 @@
                             : grid_list_.front()->IsShowingDesksTemplatesGrid();
 }
 
+void OverviewSession::UpdateAccessibilityFocus() {
+  if (is_shutting_down())
+    return;
+
+  // Construct the list of accessible widgets, these are the overview focus
+  // widget, desk bar widget, all the item widgets and the no window indicator
+  // widgets, if available.
+  std::vector<views::Widget*> a11y_widgets;
+  if (overview_focus_widget_)
+    a11y_widgets.push_back(overview_focus_widget_.get());
+
+  for (auto& grid : grid_list_) {
+    if (grid->IsSaveDeskAsTemplateButtonVisible())
+      a11y_widgets.push_back(grid->save_desk_as_template_widget());
+
+    for (const auto& item : grid->window_list())
+      a11y_widgets.push_back(item->item_widget());
+
+    if (grid->desks_widget())
+      a11y_widgets.push_back(const_cast<views::Widget*>(grid->desks_widget()));
+
+    auto* no_windows_widget = grid->no_windows_widget();
+    if (no_windows_widget) {
+      a11y_widgets.push_back(
+          static_cast<views::Widget*>(grid->no_windows_widget()));
+    }
+  }
+
+  if (a11y_widgets.empty())
+    return;
+
+  auto get_view_a11y = [&a11y_widgets](int index) -> views::ViewAccessibility& {
+    return a11y_widgets[index]->GetContentsView()->GetViewAccessibility();
+  };
+
+  // If there is only one widget left, clear the focus overrides so that they
+  // do not point to deleted objects.
+  if (a11y_widgets.size() == 1) {
+    get_view_a11y(/*index=*/0).OverridePreviousFocus(nullptr);
+    get_view_a11y(/*index=*/0).OverrideNextFocus(nullptr);
+    a11y_widgets[0]->GetContentsView()->NotifyAccessibilityEvent(
+        ax::mojom::Event::kTreeChanged, true);
+    return;
+  }
+
+  int size = a11y_widgets.size();
+  for (int i = 0; i < size; ++i) {
+    int previous_index = (i + size - 1) % size;
+    int next_index = (i + 1) % size;
+    get_view_a11y(i).OverridePreviousFocus(a11y_widgets[previous_index]);
+    get_view_a11y(i).OverrideNextFocus(a11y_widgets[next_index]);
+    a11y_widgets[i]->GetContentsView()->NotifyAccessibilityEvent(
+        ax::mojom::Event::kTreeChanged, true);
+  }
+}
+
 void OverviewSession::OnDeskAdded(const Desk* desk) {}
 void OverviewSession::OnDeskRemoved(const Desk* desk) {}
 void OverviewSession::OnDeskReordered(int old_index, int new_index) {}
@@ -1393,58 +1449,6 @@
   UpdateAccessibilityFocus();
 }
 
-void OverviewSession::UpdateAccessibilityFocus() {
-  if (is_shutting_down())
-    return;
-
-  // Construct the list of accessible widgets, these are the overview focus
-  // widget, desk bar widget, all the item widgets and the no window indicator
-  // widgets, if available.
-  std::vector<views::Widget*> a11y_widgets;
-  if (overview_focus_widget_)
-    a11y_widgets.push_back(overview_focus_widget_.get());
-
-  for (auto& grid : grid_list_) {
-    for (const auto& item : grid->window_list())
-      a11y_widgets.push_back(item->item_widget());
-    if (grid->desks_widget())
-      a11y_widgets.push_back(const_cast<views::Widget*>(grid->desks_widget()));
-
-    auto* no_windows_widget = grid->no_windows_widget();
-    if (no_windows_widget) {
-      a11y_widgets.push_back(
-          static_cast<views::Widget*>(grid->no_windows_widget()));
-    }
-  }
-
-  if (a11y_widgets.empty())
-    return;
-
-  auto get_view_a11y = [&a11y_widgets](int index) -> views::ViewAccessibility& {
-    return a11y_widgets[index]->GetContentsView()->GetViewAccessibility();
-  };
-
-  // If there is only one widget left, clear the focus overrides so that they
-  // do not point to deleted objects.
-  if (a11y_widgets.size() == 1) {
-    get_view_a11y(/*index=*/0).OverridePreviousFocus(nullptr);
-    get_view_a11y(/*index=*/0).OverrideNextFocus(nullptr);
-    a11y_widgets[0]->GetContentsView()->NotifyAccessibilityEvent(
-        ax::mojom::Event::kTreeChanged, true);
-    return;
-  }
-
-  int size = a11y_widgets.size();
-  for (int i = 0; i < size; ++i) {
-    int previous_index = (i + size - 1) % size;
-    int next_index = (i + 1) % size;
-    get_view_a11y(i).OverridePreviousFocus(a11y_widgets[previous_index]);
-    get_view_a11y(i).OverrideNextFocus(a11y_widgets[next_index]);
-    a11y_widgets[i]->GetContentsView()->NotifyAccessibilityEvent(
-        ax::mojom::Event::kTreeChanged, true);
-  }
-}
-
 bool OverviewSession::ShouldKeepOverviewOpenForDesksTemplatesDialog(
     aura::Window* gained_active,
     aura::Window* lost_active) {
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 464b61d6..6f32eb1 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -284,6 +284,11 @@
   void HideDesksTemplatesGrids();
   bool IsShowingDesksTemplatesGrid() const;
 
+  // Updates the focusable overview widgets so that they point to the correct
+  // next and previous widgets for a11y purposes. Needs to be updated when a
+  // piece of UI is shown or hidden.
+  void UpdateAccessibilityFocus();
+
   // DesksController::Observer:
   void OnDeskAdded(const Desk* desk) override;
   void OnDeskRemoved(const Desk* desk) override;
@@ -385,11 +390,6 @@
 
   void OnItemAdded(aura::Window* window);
 
-  // Updates the focusable overview widgets so that they point to the correct
-  // next and previous widgets for a11y purposes. Needs to be updated when an
-  // overview item is added or removed.
-  void UpdateAccessibilityFocus();
-
   // Called when a window is activated or deactivated and the desks templates
   // feature is enabled. Returns true if we should keep overview open. Overview
   // should be kept open if |gained_active| or |lost_active| is a desks
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index ad65fbb..b055a69 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -98,7 +98,6 @@
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/transform.h"
 #include "ui/gfx/geometry/transform_util.h"
-#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/widget/widget.h"
@@ -3142,6 +3141,11 @@
 // Tests that accessibility overrides are set as expected on overview related
 // widgets.
 TEST_P(OverviewSessionTest, AccessibilityFocusAnnotator) {
+  // If desks templates is enabled, the a11y order changes. This is tested in
+  // the desks templates test suite.
+  if (GetParam())
+    return;
+
   auto window3 = CreateTestWindow(gfx::Rect(100, 100));
   auto window2 = CreateTestWindow(gfx::Rect(100, 100));
   auto window1 = CreateTestWindow(gfx::Rect(100, 100));
@@ -3163,34 +3167,21 @@
   auto* item_widget2 = GetOverviewItemForWindow(window2.get())->item_widget();
   auto* item_widget3 = GetOverviewItemForWindow(window3.get())->item_widget();
 
-  // Helper that takes in a current widget and checks if the accessibility next
-  // and previous focus widgets match the given.
-  auto check_a11y_overrides = [](const std::string& id, views::Widget* widget,
-                                 views::Widget* expected_previous,
-                                 views::Widget* expected_next) -> void {
-    SCOPED_TRACE(id);
-    views::View* contents_view = widget->GetContentsView();
-    views::ViewAccessibility& view_accessibility =
-        contents_view->GetViewAccessibility();
-    EXPECT_EQ(expected_previous, view_accessibility.GetPreviousFocus());
-    EXPECT_EQ(expected_next, view_accessibility.GetNextFocus());
-  };
-
   // Order should be [focus_widget, item_widget1, item_widget2, item_widget3,
   // desk_widget].
-  check_a11y_overrides("focus", focus_widget, desk_widget, item_widget1);
-  check_a11y_overrides("item1", item_widget1, focus_widget, item_widget2);
-  check_a11y_overrides("item2", item_widget2, item_widget1, item_widget3);
-  check_a11y_overrides("item3", item_widget3, item_widget2, desk_widget);
-  check_a11y_overrides("desk", desk_widget, item_widget3, focus_widget);
+  CheckA11yOverrides("focus", focus_widget, desk_widget, item_widget1);
+  CheckA11yOverrides("item1", item_widget1, focus_widget, item_widget2);
+  CheckA11yOverrides("item2", item_widget2, item_widget1, item_widget3);
+  CheckA11yOverrides("item3", item_widget3, item_widget2, desk_widget);
+  CheckA11yOverrides("desk", desk_widget, item_widget3, focus_widget);
 
   // Remove |window2|. The new order should be [focus_widget, item_widget1,
   // item_widget3, desk_widget].
   window2.reset();
-  check_a11y_overrides("focus", focus_widget, desk_widget, item_widget1);
-  check_a11y_overrides("item1", item_widget1, focus_widget, item_widget3);
-  check_a11y_overrides("item3", item_widget3, item_widget1, desk_widget);
-  check_a11y_overrides("desk", desk_widget, item_widget3, focus_widget);
+  CheckA11yOverrides("focus", focus_widget, desk_widget, item_widget1);
+  CheckA11yOverrides("item1", item_widget1, focus_widget, item_widget3);
+  CheckA11yOverrides("item3", item_widget3, item_widget1, desk_widget);
+  CheckA11yOverrides("desk", desk_widget, item_widget3, focus_widget);
 }
 
 // Tests that removing a transient child during overview does not result in a
diff --git a/ash/wm/overview/overview_test_base.cc b/ash/wm/overview/overview_test_base.cc
index f5f2ac4..153dc1aaf 100644
--- a/ash/wm/overview/overview_test_base.cc
+++ b/ash/wm/overview/overview_test_base.cc
@@ -24,6 +24,7 @@
 #include "ui/compositor/layer.h"
 #include "ui/compositor/test/test_utils.h"
 #include "ui/gfx/geometry/transform_util.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
@@ -195,6 +196,18 @@
   trace_names_.push_back(trace);
 }
 
+void OverviewTestBase::CheckA11yOverrides(const std::string& trace,
+                                          views::Widget* widget,
+                                          views::Widget* expected_previous,
+                                          views::Widget* expected_next) {
+  SCOPED_TRACE(trace);
+  views::View* contents_view = widget->GetContentsView();
+  views::ViewAccessibility& view_accessibility =
+      contents_view->GetViewAccessibility();
+  EXPECT_EQ(expected_previous, view_accessibility.GetPreviousFocus());
+  EXPECT_EQ(expected_next, view_accessibility.GetNextFocus());
+}
+
 void OverviewTestBase::CheckOverviewEnterExitHistogram(
     const std::string& trace,
     const std::vector<int>& enter_counts,
diff --git a/ash/wm/overview/overview_test_base.h b/ash/wm/overview/overview_test_base.h
index 1dcc1bc..593313e 100644
--- a/ash/wm/overview/overview_test_base.h
+++ b/ash/wm/overview/overview_test_base.h
@@ -103,6 +103,13 @@
  protected:
   void CheckForDuplicateTraceName(const std::string& trace);
 
+  // Takes in a current widget and checks if the accessibility next
+  // and previous focus widgets match the given.
+  void CheckA11yOverrides(const std::string& trace,
+                          views::Widget* widget,
+                          views::Widget* expected_previous,
+                          views::Widget* expected_next);
+
   base::HistogramTester histograms_;
 
  private:
diff --git a/base/bind.h b/base/bind.h
index 1a2937f..fae8cdd 100644
--- a/base/bind.h
+++ b/base/bind.h
@@ -273,7 +273,7 @@
 // Both versions of Passed() prevent T from being an lvalue reference. The first
 // via use of enable_if, and the second takes a T* which will not bind to T&.
 template <typename T,
-          std::enable_if_t<!std::is_lvalue_reference<T>::value>* = nullptr>
+          std::enable_if_t<!std::is_lvalue_reference_v<T>>* = nullptr>
 inline internal::PassedWrapper<T> Passed(T&& scoper) {
   return internal::PassedWrapper<T>(std::move(scoper));
 }
diff --git a/base/bind_internal.h b/base/bind_internal.h
index b8670d6..45b9c6f 100644
--- a/base/bind_internal.h
+++ b/base/bind_internal.h
@@ -404,7 +404,7 @@
 template <typename Functor>
 struct FunctorTraits<Functor,
                      std::enable_if_t<IsCallableObject<Functor>::value &&
-                                      std::is_empty<Functor>::value>> {
+                                      std::is_empty_v<Functor>>> {
   using RunType = ExtractCallableRunType<Functor>;
   static constexpr bool is_method = false;
   static constexpr bool is_nullable = false;
@@ -706,7 +706,7 @@
   // WeakCalls are only supported for functions with a void return type.
   // Otherwise, the function result would be undefined if the WeakPtr<>
   // is invalidated.
-  static_assert(std::is_void<ReturnType>::value,
+  static_assert(std::is_void_v<ReturnType>,
                 "weak_ptrs can only bind to methods without return values");
 
   template <typename Functor, typename BoundWeakPtr, typename... RunArgs>
@@ -737,7 +737,7 @@
     // InvokeHelper<>::MakeItSo() call below.
     StorageType* storage = static_cast<StorageType*>(base);
     static constexpr size_t num_bound_args =
-        std::tuple_size<decltype(storage->bound_args_)>::value;
+        std::tuple_size_v<decltype(storage->bound_args_)>;
     return RunImpl(std::move(storage->functor_),
                    std::move(storage->bound_args_),
                    std::make_index_sequence<num_bound_args>(),
@@ -750,7 +750,7 @@
     // InvokeHelper<>::MakeItSo() call below.
     const StorageType* storage = static_cast<StorageType*>(base);
     static constexpr size_t num_bound_args =
-        std::tuple_size<decltype(storage->bound_args_)>::value;
+        std::tuple_size_v<decltype(storage->bound_args_)>;
     return RunImpl(storage->functor_, storage->bound_args_,
                    std::make_index_sequence<num_bound_args>(),
                    std::forward<UnboundArgs>(unbound_args)...);
@@ -842,7 +842,7 @@
                              BindStateBase::CancellationQueryMode mode) {
   const BindStateType* storage = static_cast<const BindStateType*>(base);
   static constexpr size_t num_bound_args =
-      std::tuple_size<decltype(storage->bound_args_)>::value;
+      std::tuple_size_v<decltype(storage->bound_args_)>;
   return QueryCancellationTraitsImpl(
       mode, storage->functor_, storage->bound_args_,
       std::make_index_sequence<num_bound_args>());
@@ -852,7 +852,7 @@
 template <typename Functor, typename Receiver, typename... Unused>
 std::enable_if_t<
     !(MakeFunctorTraits<Functor>::is_method &&
-      std::is_pointer<std::decay_t<Receiver>>::value &&
+      std::is_pointer_v<std::decay_t<Receiver>> &&
       IsRefCountedType<std::remove_pointer_t<std::decay_t<Receiver>>>::value)>
 BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {}
 
@@ -863,7 +863,7 @@
 template <typename Functor, typename Receiver, typename... Unused>
 std::enable_if_t<
     MakeFunctorTraits<Functor>::is_method &&
-    std::is_pointer<std::decay_t<Receiver>>::value &&
+    std::is_pointer_v<std::decay_t<Receiver>> &&
     IsRefCountedType<std::remove_pointer_t<std::decay_t<Receiver>>>::value>
 BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {
   DCHECK(receiver);
@@ -996,10 +996,10 @@
  private:
   using DecayedReceiver = std::decay_t<Receiver>;
 
-  static_assert(!std::is_array<std::remove_reference_t<Receiver>>::value,
+  static_assert(!std::is_array_v<std::remove_reference_t<Receiver>>,
                 "First bound argument to a method cannot be an array.");
   static_assert(
-      !std::is_pointer<DecayedReceiver>::value ||
+      !std::is_pointer_v<DecayedReceiver> ||
           IsRefCountedType<std::remove_pointer_t<DecayedReceiver>>::value,
       "Receivers may not be raw pointers. If using a raw pointer here is safe"
       " and has no lifetime concerns, use base::Unretained() and document why"
@@ -1010,7 +1010,7 @@
  public:
   using Type = BindState<
       std::decay_t<Functor>,
-      std::conditional_t<std::is_pointer<DecayedReceiver>::value,
+      std::conditional_t<std::is_pointer_v<DecayedReceiver>,
                          scoped_refptr<std::remove_pointer_t<DecayedReceiver>>,
                          DecayedReceiver>,
       MakeStorageType<BoundArgs>...>;
@@ -1098,25 +1098,25 @@
     template <typename FunctorParamType>
     struct ToParamWithType {
       static constexpr bool kCanBeForwardedToBoundFunctor =
-          std::is_constructible<FunctorParamType, ForwardingType>::value;
+          std::is_constructible_v<FunctorParamType, ForwardingType>;
 
       // If the bound type can't be forwarded then test if `FunctorParamType` is
       // a non-const lvalue reference and a reference to the unwrapped type
       // *could* have been successfully forwarded.
       static constexpr bool kNonConstRefParamMustBeWrapped =
           kCanBeForwardedToBoundFunctor ||
-          !(std::is_lvalue_reference<FunctorParamType>::value &&
-            !std::is_const<std::remove_reference_t<FunctorParamType>>::value &&
-            std::is_convertible<std::decay_t<ForwardingType>&,
-                                FunctorParamType>::value);
+          !(std::is_lvalue_reference_v<FunctorParamType> &&
+            !std::is_const_v<std::remove_reference_t<FunctorParamType>> &&
+            std::is_convertible_v<std::decay_t<ForwardingType>&,
+                                  FunctorParamType>);
 
       // Note that this intentionally drops the const qualifier from
       // `ForwardingType`, to test if it *could* have been successfully
       // forwarded if `Passed()` had been used.
       static constexpr bool kMoveOnlyTypeMustUseBasePassed =
           kCanBeForwardedToBoundFunctor ||
-          !std::is_constructible<FunctorParamType,
-                                 std::decay_t<ForwardingType>&&>::value;
+          !std::is_constructible_v<FunctorParamType,
+                                   std::decay_t<ForwardingType>&&>;
     };
   };
 
@@ -1125,14 +1125,13 @@
     template <typename StorageType>
     struct StoredAs {
       static constexpr bool kBindArgumentCanBeCaptured =
-          std::is_constructible<StorageType, BoundAsType>::value;
+          std::is_constructible_v<StorageType, BoundAsType>;
       // Note that this intentionally drops the const qualifier from
       // `BoundAsType`, to test if it *could* have been successfully bound if
       // `std::move()` had been used.
       static constexpr bool kMoveOnlyTypeMustUseStdMove =
           kBindArgumentCanBeCaptured ||
-          !std::is_constructible<StorageType,
-                                 std::decay_t<BoundAsType>&&>::value;
+          !std::is_constructible_v<StorageType, std::decay_t<BoundAsType>&&>;
     };
   };
 };
@@ -1228,23 +1227,6 @@
 struct AssertBindArgIsNotBasePassed<PassedWrapper<T>> : public std::false_type {
 };
 
-// Used below in BindImpl to determine whether to use Invoker::Run or
-// Invoker::RunOnce.
-// Note: Simply using `kIsOnce ? &Invoker::RunOnce : &Invoker::Run` does not
-// work, since the compiler needs to check whether both expressions are
-// well-formed. Using `Invoker::Run` with a OnceCallback triggers a
-// static_assert, which is why the ternary expression does not compile.
-// TODO(crbug.com/752720): Remove this indirection once we have `if constexpr`.
-template <typename Invoker>
-constexpr auto GetInvokeFunc(std::true_type) {
-  return Invoker::RunOnce;
-}
-
-template <typename Invoker>
-constexpr auto GetInvokeFunc(std::false_type) {
-  return Invoker::Run;
-}
-
 template <template <typename> class CallbackT,
           typename Functor,
           typename... Args>
@@ -1274,8 +1256,12 @@
   // InvokeFuncStorage, so that we can ensure its type matches to
   // PolymorphicInvoke, to which CallbackType will cast back.
   using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
-  PolymorphicInvoke invoke_func =
-      GetInvokeFunc<Invoker>(bool_constant<kIsOnce>());
+  PolymorphicInvoke invoke_func;
+  if constexpr (kIsOnce) {
+    invoke_func = Invoker::RunOnce;
+  } else {
+    invoke_func = Invoker::Run;
+  }
 
   using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
   return CallbackType(BindState::Create(
@@ -1289,9 +1275,8 @@
 // crashes.
 template <template <typename> class CallbackT,
           typename Signature,
-          std::enable_if_t<std::is_same<CallbackT<Signature>,
-                                        OnceCallback<Signature>>::value>* =
-              nullptr>
+          std::enable_if_t<std::is_same_v<CallbackT<Signature>,
+                                          OnceCallback<Signature>>>* = nullptr>
 OnceCallback<Signature> BindImpl(OnceCallback<Signature> callback) {
   CHECK(callback);
   return callback;
@@ -1299,9 +1284,8 @@
 
 template <template <typename> class CallbackT,
           typename Signature,
-          std::enable_if_t<std::is_same<CallbackT<Signature>,
-                                        OnceCallback<Signature>>::value>* =
-              nullptr>
+          std::enable_if_t<std::is_same_v<CallbackT<Signature>,
+                                          OnceCallback<Signature>>>* = nullptr>
 OnceCallback<Signature> BindImpl(RepeatingCallback<Signature> callback) {
   CHECK(callback);
   return callback;
@@ -1309,8 +1293,8 @@
 
 template <template <typename> class CallbackT,
           typename Signature,
-          std::enable_if_t<std::is_same<CallbackT<Signature>,
-                                        RepeatingCallback<Signature>>::value>* =
+          std::enable_if_t<std::is_same_v<CallbackT<Signature>,
+                                          RepeatingCallback<Signature>>>* =
               nullptr>
 RepeatingCallback<Signature> BindImpl(RepeatingCallback<Signature> callback) {
   CHECK(callback);
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc
index 134841c3..8304644 100644
--- a/base/bind_unittest.nc
+++ b/base/bind_unittest.nc
@@ -94,7 +94,7 @@
   method_to_const_cb.Run();
 }
 
-#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: static_assert failed due to requirement '!std::is_pointer<base::NoRef *>::value || IsRefCountedType<base::NoRef, void>::value' \"Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained() and document why it's safe.\""]
+#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: static_assert failed due to requirement '!std::is_pointer_v<base::NoRef *> || IsRefCountedType<base::NoRef, void>::value' \"Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained() and document why it's safe.\""]
 
 
 // Method bound to non-refcounted object.
@@ -107,7 +107,7 @@
   no_ref_cb.Run();
 }
 
-#elif defined(NCTEST_CONST_METHOD_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: static_assert failed due to requirement '!std::is_pointer<base::NoRef *>::value || IsRefCountedType<base::NoRef, void>::value' \"Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained() and document why it's safe.\""]
+#elif defined(NCTEST_CONST_METHOD_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: static_assert failed due to requirement '!std::is_pointer_v<base::NoRef *> || IsRefCountedType<base::NoRef, void>::value' \"Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained() and document why it's safe.\""]
 
 // Const Method bound to non-refcounted object.
 //
@@ -196,7 +196,7 @@
   auto cb = BindOnce(&TakesIntRef, base::OwnedRef(f));
 }
 
-#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION)  // [r"fatal error: static_assert failed due to requirement '!std::is_array<base::HasRef\[10\]>::value' \"First bound argument to a method cannot be an array.\""]
+#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION)  // [r"fatal error: static_assert failed due to requirement '!std::is_array_v<base::HasRef\[10\]>' \"First bound argument to a method cannot be an array.\""]
 
 // A method should not be bindable with an array of objects.
 //
@@ -249,7 +249,7 @@
       BindRepeating(&VoidPolymorphic1<const HasRef*>, for_raw_ptr);
 }
 
-#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID)  // [r"fatal error: static_assert failed due to requirement 'std::is_void<int>::value' \"weak_ptrs can only bind to methods without return values\""]
+#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID)  // [r"fatal error: static_assert failed due to requirement 'std::is_void_v<int>' \"weak_ptrs can only bind to methods without return values\""]
 
 // WeakPtrs cannot be bound to methods with return types.
 void WontCompile() {
diff --git a/base/callback_internal.h b/base/callback_internal.h
index bfef610..0bb53e8a 100644
--- a/base/callback_internal.h
+++ b/base/callback_internal.h
@@ -38,7 +38,7 @@
 };
 
 template <typename T>
-using PassingType = std::conditional_t<std::is_scalar<T>::value, T, T&&>;
+using PassingType = std::conditional_t<std::is_scalar_v<T>, T, T&&>;
 
 // BindStateBase is used to provide an opaque handle that the Callback
 // class can use to represent a function object with bound arguments.  It
@@ -231,7 +231,7 @@
                 "has a non-void return type.");
   // TODO(dcheng): This should probably check is_convertible as well (same with
   // `AssertBindArgsValidity`).
-  static_assert(std::is_constructible<ThenArgs..., OriginalR&&>::value,
+  static_assert(std::is_constructible_v<ThenArgs..., OriginalR&&>,
                 "|then| callback's parameter must be constructible from "
                 "return type of |this|.");
 
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index 2bbe59b..1bc53b3 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -33,11 +33,6 @@
 namespace base {
 
 bool IsWprintfFormatPortable(const wchar_t* format) {
-  // This snippet of code checks that we can build C++17 code.
-  // TODO(thakis): Remove this again in a bit.
-  if constexpr (constexpr int i = 0; i > 0) {
-  }
-
   for (const wchar_t* position = format; *position != '\0'; ++position) {
     if (*position == '%') {
       bool in_specification = true;
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 63911f0..efb48b755 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -170,6 +170,7 @@
 class CategorizedWorkerPool;
 class DesktopCaptureDevice;
 class DWriteFontCollectionProxy;
+class DWriteFontProxyImpl;
 class EmergencyTraceFinalisationCoordinator;
 class InProcessUtilityThread;
 class NestedMessagePumpAndroid;
@@ -445,6 +446,7 @@
   friend class blink::DiskDataAllocator;
   friend class chromecast::CrashUtil;
   friend class content::BrowserProcessIOThread;
+  friend class content::DWriteFontProxyImpl;
   friend class content::NetworkServiceInstancePrivate;
   friend class content::PepperPrintSettingsManagerImpl;
   friend class content::RenderProcessHostImpl;
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 7c8f770..cfd6ca1c 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-7.20220112.0.1
+7.20220112.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 7c8f770..cfd6ca1c 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-7.20220112.0.1
+7.20220112.1.1
diff --git a/build/lacros/test_runner.py b/build/lacros/test_runner.py
index 4ec763f..5719239 100755
--- a/build/lacros/test_runner.py
+++ b/build/lacros/test_runner.py
@@ -350,6 +350,18 @@
   return None
 
 
+def _IsRunningOnBots(forward_args):
+  """Detects if the script is running on bots or not.
+
+  Args:
+    forward_args (list): Args to be forwarded to the test command.
+
+  Returns:
+    True if the script is running on bots. Otherwise returns False.
+  """
+  return '--test-launcher-bot-mode' in forward_args
+
+
 def _RunTestWithAshChrome(args, forward_args):
   """Runs tests with ash-chrome.
 
@@ -443,6 +455,13 @@
     log = None
     if args.ash_logging_path:
       log = open(args.ash_logging_path, 'a')
+    # Ash logs can be useful. Enable ash log by default on bots.
+    elif _IsRunningOnBots(forward_args):
+      summary_file = _ParseSummaryOutput(forward_args)
+      if summary_file:
+        ash_log_path = os.path.join(os.path.dirname(summary_file),
+                                    'ash_chrome.log')
+        log = open(ash_log_path, 'a')
 
     while not ash_process_has_started and num_tries < total_tries:
       num_tries += 1
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 703f212..792063e 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -3596,7 +3596,7 @@
     constexpr float kCustomWhiteLevel = 200.f;
     auto display_cs = gfx::DisplayColorSpaces(raster_cs);
     if (raster_cs.IsHDR())
-      display_cs.SetSDRWhiteLevel(kCustomWhiteLevel);
+      display_cs.SetSDRMaxLuminanceNits(kCustomWhiteLevel);
 
     pending_layer()->layer_tree_impl()->SetDisplayColorSpaces(display_cs);
     PictureLayerTilingSet* tiling_set =
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 8d6c612c..cd2da1af 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1958,9 +1958,9 @@
 
   // The pending tree will has the most recently updated color space, so use it.
   if (pending_tree_)
-    return pending_tree_->display_color_spaces().GetSDRWhiteLevel();
+    return pending_tree_->display_color_spaces().GetSDRMaxLuminanceNits();
   if (active_tree_)
-    return active_tree_->display_color_spaces().GetSDRWhiteLevel();
+    return active_tree_->display_color_spaces().GetSDRMaxLuminanceNits();
   return gfx::ColorSpace::kDefaultSDRWhiteLevel;
 }
 
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 05f9cf4..0973c6e 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -16329,7 +16329,7 @@
   constexpr float kCustomWhiteLevel = 200.f;
   auto hdr = gfx::ColorSpace::CreateHDR10();
   auto display_cs = gfx::DisplayColorSpaces(hdr);
-  display_cs.SetSDRWhiteLevel(kCustomWhiteLevel);
+  display_cs.SetSDRMaxLuminanceNits(kCustomWhiteLevel);
 
   LayerTreeSettings settings = DefaultSettings();
   CreateHostImpl(settings, CreateLayerTreeFrameSink());
diff --git a/chrome/VERSION b/chrome/VERSION
index 444224c..08c83e9 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=99
 MINOR=0
-BUILD=4825
+BUILD=4826
 PATCH=0
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
index f3989f0..29c63627 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -535,11 +535,8 @@
                                      : R.style.ThemeOverlay_Feed_Light));
         ProcessScope processScope = FeedSurfaceTracker.getInstance().getXSurfaceProcessScope();
         if (processScope != null) {
-            mDependencyProvider = new FeedSurfaceScopeDependencyProvider(
-                    mActivity, context, mShowDarkBackground, () -> {
-                        if (mMediator.getFirstStream() == null) return false;
-                        return mMediator.getFirstStream().isActivityLoggingEnabled();
-                    });
+            mDependencyProvider =
+                    new FeedSurfaceScopeDependencyProvider(mActivity, context, mShowDarkBackground);
 
             mSurfaceScope = processScope.obtainSurfaceScope(mDependencyProvider);
             if (mScrollableContainerDelegate != null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
index 989b4ffa..9a744be 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -42,7 +42,6 @@
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.JniMocker;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
@@ -50,8 +49,6 @@
 import org.chromium.chrome.browser.omnibox.suggestions.header.HeaderProcessor;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
-import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.components.metrics.OmniboxEventProtos.OmniboxEventProto.PageClassification;
 import org.chromium.components.omnibox.AutocompleteMatch;
 import org.chromium.components.omnibox.AutocompleteMatchBuilder;
@@ -296,23 +293,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
-    public void updateSuggestionsList_notEffectiveWhenDisabled() {
-        mMediator.onNativeInitialized();
-
-        final int maximumListHeight = SUGGESTION_MIN_HEIGHT * 2;
-
-        mMediator.onSuggestionDropdownHeightChanged(maximumListHeight);
-        mMediator.onSuggestionsReceived(AutocompleteResult.fromCache(mSuggestionsList, null), "");
-
-        Assert.assertEquals(mSuggestionsList.size(), mSuggestionModels.size());
-        Assert.assertTrue(mListModel.get(SuggestionListProperties.VISIBLE));
-    }
-
-    @Test
-    @SmallTest
-    @UiThreadTest
-    @EnableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void updateSuggestionsList_worksWithNullList() {
         mMediator.onNativeInitialized();
 
@@ -328,7 +308,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @EnableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void updateSuggestionsList_worksWithEmptyList() {
         mMediator.onNativeInitialized();
 
@@ -344,7 +323,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @EnableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void updateSuggestionsList_scrolEventsWithConcealedItemsTogglesKeyboardVisibility() {
         mMediator.onNativeInitialized();
 
@@ -373,7 +351,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @EnableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void updateSuggestionsList_updateHeightWhenHardwareKeyboardIsConnected() {
         // Simulates behavior of physical keyboard being attached to the device.
         // In this scenario, requesting keyboard to come up will not result with an actual
@@ -416,7 +393,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @EnableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void updateSuggestionsList_rejectsHeightUpdatesWhenKeyboardIsHidden() {
         // Simulates scenario where we receive dropdown height update after software keyboard is
         // explicitly hidden. In this scenario the updates should be rejected when estimating
@@ -446,7 +422,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onTextChanged_emptyTextTriggersZeroSuggest() {
         when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true);
         when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false);
@@ -466,7 +441,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onTextChanged_nonEmptyTextTriggersSuggestions() {
         String url = "http://www.example.com";
         int pageClassification = PageClassification.BLANK_VALUE;
@@ -485,7 +459,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onTextChanged_cancelsPendingRequests() {
         String url = "http://www.example.com";
         int pageClassification = PageClassification.BLANK_VALUE;
@@ -508,7 +481,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onUrlFocusChange_onlyOneZeroSuggestRequestIsInvoked() {
         when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true);
         when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false);
@@ -537,7 +509,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onUrlFocusChange_preventsZeroSuggestRequestOnFocusLost() {
         when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true);
         when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false);
@@ -564,7 +535,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onUrlFocusChange_textChangeCancelsOustandingZeroSuggestRequest() {
         when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true);
         when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false);
@@ -598,7 +568,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onUrlFocusChange_textChangeCancelsIntermediateZeroSuggestRequests() {
         when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true);
         when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false);
@@ -629,7 +598,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onSuggestionsReceived_sendsOnSuggestionsChanged() {
         mMediator.onNativeInitialized();
         mMediator.onSuggestionsReceived(
@@ -645,7 +613,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void setLayoutDirection_beforeInitialization() {
         mMediator.onNativeInitialized();
         mMediator.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
@@ -663,7 +630,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void setLayoutDirection_afterInitialization() {
         mMediator.onNativeInitialized();
         mMediator.onSuggestionDropdownHeightChanged(Integer.MAX_VALUE);
@@ -690,7 +656,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onUrlFocusChange_triggersZeroSuggest_nativeInitialized() {
         when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true);
         when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false);
@@ -711,7 +676,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onUrlFocusChange_triggersZeroSuggest_nativeNotInitialized() {
         when(mAutocompleteDelegate.isUrlBarFocused()).thenReturn(true);
         when(mAutocompleteDelegate.didFocusUrlFromFakebox()).thenReturn(false);
@@ -737,7 +701,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     public void onTextChanged_editSessionActivatedByUserInput() {
         mMediator.onNativeInitialized();
         mMediator.onUrlFocusChange(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java
index fbebfd8..37ec39f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilderUnitTest.java
@@ -31,12 +31,9 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.Batch;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
 import org.chromium.chrome.browser.omnibox.suggestions.header.HeaderProcessor;
 import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
-import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.components.omnibox.AutocompleteMatch;
 import org.chromium.components.omnibox.AutocompleteMatchBuilder;
 import org.chromium.components.omnibox.AutocompleteResult;
@@ -222,7 +219,6 @@
         verifyNoMoreInteractions(mMockSuggestionProcessor);
     }
 
-    @DisableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     @Test
     @SmallTest
     @UiThreadTest
@@ -349,7 +345,6 @@
         Assert.assertEquals(1, mBuilder.getVisibleSuggestionsCount(result));
     }
 
-    @EnableFeatures(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT)
     @Test
     @SmallTest
     @UiThreadTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
index 78d2b71..2e3dc22 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/SearchActivityTest.java
@@ -52,7 +52,6 @@
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.app.metrics.LaunchCauseMetrics;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.locale.LocaleManagerDelegate;
@@ -77,7 +76,6 @@
 import org.chromium.chrome.test.MultiActivityTestRule;
 import org.chromium.chrome.test.util.ActivityTestUtils;
 import org.chromium.chrome.test.util.OmniboxTestUtils;
-import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.browser_ui.share.ClipboardImageFileProvider;
 import org.chromium.components.omnibox.AutocompleteMatch;
 import org.chromium.components.omnibox.AutocompleteMatchBuilder;
@@ -553,8 +551,6 @@
     @Test
     @SmallTest
     @DisabledTest(message = "https://crbug.com/1144676")
-    @Features.
-    EnableFeatures({ChromeFeatureList.OMNIBOX_ENABLE_CLIPBOARD_PROVIDER_IMAGE_SUGGESTIONS})
     public void testImageSearch() throws InterruptedException, Exception {
         // Put an image into system clipboard.
         putAnImageIntoClipboard();
@@ -627,8 +623,6 @@
     @Test
     @SmallTest
     @DisabledTest(message = "https://crbug.com/1144676")
-    @Features.
-    EnableFeatures({ChromeFeatureList.OMNIBOX_ENABLE_CLIPBOARD_PROVIDER_IMAGE_SUGGESTIONS})
     public void testImageSearch_OnlyTrustedIntentCanPost() throws InterruptedException, Exception {
         // Put an image into system clipboard.
         putAnImageIntoClipboard();
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4fb2ca1..f8657bd 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3125,6 +3125,8 @@
       "feed/android/feed_service_factory.h",
       "feed/android/feed_stream.cc",
       "feed/android/feed_stream.h",
+      "feed/android/jni_translation.cc",
+      "feed/android/jni_translation.h",
       "feed/android/refresh_task_scheduler_impl.cc",
       "feed/android/refresh_task_scheduler_impl.h",
       "feed/android/rss_links_fetcher.cc",
@@ -4276,6 +4278,8 @@
       "support_tool/support_tool_handler.h",
       "support_tool/support_tool_util.cc",
       "support_tool/support_tool_util.h",
+      "support_tool/system_log_source_data_collector_adaptor.cc",
+      "support_tool/system_log_source_data_collector_adaptor.h",
       "sync/glue/extension_model_type_controller.cc",
       "sync/glue/extension_model_type_controller.h",
       "sync/glue/extension_setting_model_type_controller.cc",
@@ -4719,6 +4723,10 @@
       "nearby_sharing/fast_initiation/fast_initiation_scanner.h",
       "nearby_sharing/fast_initiation/fast_initiation_scanner_feature_usage_metrics.cc",
       "nearby_sharing/fast_initiation/fast_initiation_scanner_feature_usage_metrics.h",
+      "nearby_sharing/firewall_hole/nearby_connections_firewall_hole.cc",
+      "nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h",
+      "nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.cc",
+      "nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h",
       "nearby_sharing/incoming_frames_reader.cc",
       "nearby_sharing/incoming_frames_reader.h",
       "nearby_sharing/incoming_share_target_info.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index efb5d7c..2f2700b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1213,6 +1213,12 @@
     {"15", kMaxZeroSuggestMatches15, base::size(kMaxZeroSuggestMatches15),
      nullptr}};
 
+const FeatureEntry::FeatureVariation
+    kOmniboxTrendingZeroPrefixSuggestionsOnNTPVariations[] = {
+        {"Signed-in Users", {}, 0, "t4693175"},
+        {"Signed-out Users", {}, 0, "t4693176"},
+        {"All Users", {}, 0, "t4693177"}};
+
 constexpr FeatureEntry::FeatureParam kOmniboxZeroSuggestCacheDuration15Secs[] =
     {{"ZeroSuggestCacheDurationSec", "15"}};
 constexpr FeatureEntry::FeatureParam
@@ -3253,10 +3259,6 @@
      flag_descriptions::kMicrophoneMuteSwitchDeviceName,
      flag_descriptions::kMicrophoneMuteSwitchDeviceDescription, kOsCrOS,
      SINGLE_VALUE_TYPE("enable-microphone-mute-switch-device")},
-    {"show-feedback-report-questionnaire",
-     flag_descriptions::kShowFeedbackReportQuestionnaireName,
-     flag_descriptions::kShowFeedbackReportQuestionnaireDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kShowFeedbackReportQuestionnaire)},
     {"wifi-connect-mac-address-randomization",
      flag_descriptions::kWifiConnectMacAddressRandomizationName,
      flag_descriptions::kWifiConnectMacAddressRandomizationDescription, kOsCrOS,
@@ -4541,7 +4543,10 @@
      flag_descriptions::kOmniboxTrendingZeroPrefixSuggestionsOnNTPName,
      flag_descriptions::kOmniboxTrendingZeroPrefixSuggestionsOnNTPDescription,
      kOsAll,
-     FEATURE_VALUE_TYPE(omnibox::kOmniboxTrendingZeroPrefixSuggestionsOnNTP)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(
+         omnibox::kOmniboxTrendingZeroPrefixSuggestionsOnNTP,
+         kOmniboxTrendingZeroPrefixSuggestionsOnNTPVariations,
+         "OmniboxBundledExperimentV1")},
 
     {"omnibox-zero-suggest-prefetching",
      flag_descriptions::kOmniboxZeroSuggestPrefetchingName,
@@ -6949,16 +6954,6 @@
      FEATURE_VALUE_TYPE(chrome_pdf::features::kPdfXfaSupport)},
 #endif  // BUILDFLAG(ENABLE_PDF)
 
-    {"send-tab-to-self-when-signed-in",
-     flag_descriptions::kSendTabToSelfWhenSignedInName,
-     flag_descriptions::kSendTabToSelfWhenSignedInDescription, kOsAll,
-     FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfWhenSignedIn)},
-
-    {"send-tab-to-self-manage-devices-link",
-     flag_descriptions::kSendTabToSelfManageDevicesLinkName,
-     flag_descriptions::kSendTabToSelfManageDevicesLinkDescription, kOsAll,
-     FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfManageDevicesLink)},
-
 #if defined(OS_ANDROID)
     {"send-tab-to-self-v2", flag_descriptions::kSendTabToSelfV2Name,
      flag_descriptions::kSendTabToSelfV2Description, kOsAndroid,
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
index dcc8cae6..3e3b817 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -1017,135 +1017,139 @@
       profile, user, std::move(callback));
 }
 
-void ChromeBrowserMainPartsAsh::PostProfileInit() {
+void ChromeBrowserMainPartsAsh::PostProfileInit(Profile* profile,
+                                                bool is_initial_profile) {
   // -- This used to be in ChromeBrowserMainParts::PreMainMessageLoopRun()
   // -- just after CreateProfile().
 
-  if (ProfileHelper::IsSigninProfile(profile())) {
-    // Flush signin profile if it is just created (new device or after recovery)
-    // to ensure it is correctly persisted.
-    if (profile()->IsNewProfile())
-      ProfileHelper::Get()->FlushProfile(profile());
+  if (is_initial_profile) {
+    if (ProfileHelper::IsSigninProfile(profile)) {
+      // Flush signin profile if it is just created (new device or after
+      // recovery) to ensure it is correctly persisted.
+      if (profile->IsNewProfile())
+        ProfileHelper::Get()->FlushProfile(profile);
 
-    ApplySigninProfileModifications(profile());
-  } else {
-    // Force loading of signin profile if it was not loaded before. It is
-    // possible when we are restoring session or skipping login screen for some
-    // other reason.
-    ProfileHelper::GetSigninProfile();
-  }
+      ApplySigninProfileModifications(profile);
+    } else {
+      // Force loading of signin profile if it was not loaded before. It is
+      // possible when we are restoring session or skipping login screen for
+      // some other reason.
+      ProfileHelper::GetSigninProfile();
+    }
 
-  if (base::FeatureList::IsEnabled(features::kImeSystemEmojiPicker)) {
-    ui::SetShowEmojiKeyboardCallback(
-        base::BindRepeating(&EmojiUI::Show, base::Unretained(profile())));
-  }
+    if (base::FeatureList::IsEnabled(features::kImeSystemEmojiPicker)) {
+      ui::SetShowEmojiKeyboardCallback(
+          base::BindRepeating(&EmojiUI::Show, base::Unretained(profile)));
+    }
 
-  BootTimesRecorder::Get()->OnChromeProcessStart();
+    BootTimesRecorder::Get()->OnChromeProcessStart();
 
-  // Initialize the network portal detector for Chrome OS. The network
-  // portal detector starts to listen for notifications from
-  // NetworkStateHandler and initiates captive portal detection for
-  // active networks. Should be called before call to initialize
-  // ChromeSessionManager because it depends on NetworkPortalDetector.
-  InitializeNetworkPortalDetector();
-  {
+    // Initialize the network portal detector for Chrome OS. The network
+    // portal detector starts to listen for notifications from
+    // NetworkStateHandler and initiates captive portal detection for
+    // active networks. Should be called before call to initialize
+    // ChromeSessionManager because it depends on NetworkPortalDetector.
+    InitializeNetworkPortalDetector();
+    {
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-    bool is_official_build = true;
+      bool is_official_build = true;
 #else
-    bool is_official_build = false;
+      bool is_official_build = false;
 #endif
-    // Enable portal detector if EULA was previously accepted or if
-    // this is an unofficial build.
-    if (!is_official_build || StartupUtils::IsEulaAccepted())
-      network_portal_detector::GetInstance()->Enable(true);
+      // Enable portal detector if EULA was previously accepted or if
+      // this is an unofficial build.
+      if (!is_official_build || StartupUtils::IsEulaAccepted())
+        network_portal_detector::GetInstance()->Enable(true);
+    }
+
+    // Initialize an observer to update NetworkHandler's pref based services.
+    network_pref_state_observer_ = std::make_unique<NetworkPrefStateObserver>();
+
+    if (features::IsBluetoothRevampEnabled()) {
+      // Initialize an observer to update CrosBluetoothConfig's pref based
+      // services.
+      bluetooth_pref_state_observer_ =
+          std::make_unique<BluetoothPrefStateObserver>();
+    }
+
+    // Initialize the NetworkHealth aggregator.
+    network_health::NetworkHealthService::GetInstance();
+
+    // Create the service connection to CrosHealthd platform service instance.
+    auto* cros_healthd = cros_healthd::ServiceConnection::GetInstance();
+
+    // Pass a callback to the CrosHealthd service connection that binds a
+    // pending remote to service.
+    cros_healthd->SetBindNetworkHealthServiceCallback(base::BindRepeating([] {
+      return network_health::NetworkHealthService::GetInstance()
+          ->GetHealthRemoteAndBindReceiver();
+    }));
+
+    // Pass a callback to the CrosHealthd service connection that binds a
+    // pending remote to the interface.
+    cros_healthd->SetBindNetworkDiagnosticsRoutinesCallback(
+        base::BindRepeating([] {
+          return network_health::NetworkHealthService::GetInstance()
+              ->GetDiagnosticsRemoteAndBindReceiver();
+        }));
+
+    // Initialize input methods.
+    input_method::InputMethodManager* manager =
+        input_method::InputMethodManager::Get();
+    // TODO(crbug/1264581): Remove this object once kDeviceI18nShortcutsEnabled
+    // policy is deprecated.
+    UserSessionManager* session_manager = UserSessionManager::GetInstance();
+    DCHECK(manager);
+    DCHECK(session_manager);
+
+    manager->SetState(session_manager->GetDefaultIMEState(profile));
+
+    bool is_running_test = !!parameters().ui_task;
+    g_browser_process->platform_part()->session_manager()->Initialize(
+        parsed_command_line(), profile, is_running_test);
+
+    // Guest user profile is never initialized with locale settings,
+    // so we need special handling for Guest session.
+    if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
+      SetGuestLocale(profile);
+
+    renderer_freezer_ = std::make_unique<RendererFreezer>(
+        std::make_unique<FreezerCgroupProcessManager>());
+
+    power_metrics_reporter_ = std::make_unique<PowerMetricsReporter>(
+        PowerManagerClient::Get(), g_browser_process->local_state());
+
+    g_browser_process->platform_part()->InitializeAutomaticRebootManager();
+    user_removal_manager::RemoveUsersIfNeeded();
+
+    // This observer cannot be created earlier because it requires the shell to
+    // be available.
+    idle_action_warning_observer_ =
+        std::make_unique<IdleActionWarningObserver>();
+
+    if (!user_manager::UserManager::Get()->IsLoggedInAsGuest()) {
+      // Start watching for low disk space events to notify the user if it is
+      // not a guest profile.
+      low_disk_notification_ = std::make_unique<LowDiskNotification>();
+    }
+
+    gnubby_notification_ = std::make_unique<GnubbyNotification>();
+    demo_mode_resources_remover_ = DemoModeResourcesRemover::CreateIfNeeded(
+        g_browser_process->local_state());
+
+    login_screen_extensions_lifetime_manager_ =
+        std::make_unique<LoginScreenExtensionsLifetimeManager>();
+    login_screen_extensions_storage_cleaner_ =
+        std::make_unique<LoginScreenExtensionsStorageCleaner>();
+
+    quick_answers_controller_ = std::make_unique<QuickAnswersControllerImpl>();
+    QuickAnswersController::Get()->SetClient(
+        std::make_unique<quick_answers::QuickAnswersClient>(
+            g_browser_process->shared_url_loader_factory(),
+            QuickAnswersController::Get()->GetQuickAnswersDelegate()));
   }
 
-  // Initialize an observer to update NetworkHandler's pref based services.
-  network_pref_state_observer_ = std::make_unique<NetworkPrefStateObserver>();
-
-  if (features::IsBluetoothRevampEnabled()) {
-    // Initialize an observer to update CrosBluetoothConfig's pref based
-    // services.
-    bluetooth_pref_state_observer_ =
-        std::make_unique<BluetoothPrefStateObserver>();
-  }
-
-  // Initialize the NetworkHealth aggregator.
-  network_health::NetworkHealthService::GetInstance();
-
-  // Create the service connection to CrosHealthd platform service instance.
-  auto* cros_healthd = cros_healthd::ServiceConnection::GetInstance();
-
-  // Pass a callback to the CrosHealthd service connection that binds a pending
-  // remote to service.
-  cros_healthd->SetBindNetworkHealthServiceCallback(base::BindRepeating([] {
-    return network_health::NetworkHealthService::GetInstance()
-        ->GetHealthRemoteAndBindReceiver();
-  }));
-
-  // Pass a callback to the CrosHealthd service connection that binds a pending
-  // remote to the interface.
-  cros_healthd->SetBindNetworkDiagnosticsRoutinesCallback(
-      base::BindRepeating([] {
-        return network_health::NetworkHealthService::GetInstance()
-            ->GetDiagnosticsRemoteAndBindReceiver();
-      }));
-
-  // Initialize input methods.
-  input_method::InputMethodManager* manager =
-      input_method::InputMethodManager::Get();
-  // TODO(crbug/1264581): Remove this object once kDeviceI18nShortcutsEnabled
-  // policy is deprecated.
-  UserSessionManager* session_manager = UserSessionManager::GetInstance();
-  DCHECK(manager);
-  DCHECK(session_manager);
-
-  manager->SetState(session_manager->GetDefaultIMEState(profile()));
-
-  bool is_running_test = !!parameters().ui_task;
-  g_browser_process->platform_part()->session_manager()->Initialize(
-      parsed_command_line(), profile(), is_running_test);
-
-  // Guest user profile is never initialized with locale settings,
-  // so we need special handling for Guest session.
-  if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
-    SetGuestLocale(profile());
-
-  renderer_freezer_ = std::make_unique<RendererFreezer>(
-      std::make_unique<FreezerCgroupProcessManager>());
-
-  power_metrics_reporter_ = std::make_unique<PowerMetricsReporter>(
-      PowerManagerClient::Get(), g_browser_process->local_state());
-
-  g_browser_process->platform_part()->InitializeAutomaticRebootManager();
-  user_removal_manager::RemoveUsersIfNeeded();
-
-  // This observer cannot be created earlier because it requires the shell to be
-  // available.
-  idle_action_warning_observer_ = std::make_unique<IdleActionWarningObserver>();
-
-  if (!user_manager::UserManager::Get()->IsLoggedInAsGuest()) {
-    // Start watching for low disk space events to notify the user if it is not
-    // a guest profile.
-    low_disk_notification_ = std::make_unique<LowDiskNotification>();
-  }
-
-  gnubby_notification_ = std::make_unique<GnubbyNotification>();
-  demo_mode_resources_remover_ = DemoModeResourcesRemover::CreateIfNeeded(
-      g_browser_process->local_state());
-
-  login_screen_extensions_lifetime_manager_ =
-      std::make_unique<LoginScreenExtensionsLifetimeManager>();
-  login_screen_extensions_storage_cleaner_ =
-      std::make_unique<LoginScreenExtensionsStorageCleaner>();
-
-  quick_answers_controller_ = std::make_unique<QuickAnswersControllerImpl>();
-  QuickAnswersController::Get()->SetClient(
-      std::make_unique<quick_answers::QuickAnswersClient>(
-          g_browser_process->shared_url_loader_factory(),
-          QuickAnswersController::Get()->GetQuickAnswersDelegate()));
-
-  ChromeBrowserMainPartsLinux::PostProfileInit();
+  ChromeBrowserMainPartsLinux::PostProfileInit(profile, is_initial_profile);
 }
 
 void ChromeBrowserMainPartsAsh::PreBrowserStart() {
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.h b/chrome/browser/ash/chrome_browser_main_parts_ash.h
index adc5c51..bb0d588b 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.h
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.h
@@ -138,7 +138,7 @@
 
   // Stages called from PreMainMessageLoopRun.
   void PreProfileInit() override;
-  void PostProfileInit() override;
+  void PostProfileInit(Profile* profile, bool is_initial_profile) override;
   void PreBrowserStart() override;
   void PostBrowserStart() override;
 
diff --git a/chrome/browser/ash/crostini/crostini_browser_test_util.cc b/chrome/browser/ash/crostini/crostini_browser_test_util.cc
index 392337f..7ef5397 100644
--- a/chrome/browser/ash/crostini/crostini_browser_test_util.cc
+++ b/chrome/browser/ash/crostini/crostini_browser_test_util.cc
@@ -69,7 +69,11 @@
   // Ideally we'd call SetConnectionType in PostCreateThreads, but currently we
   // have to wait for PreProfileInit to complete, since that creatse the
   // ash::Shell that AshService needs in order to start.
-  void PostProfileInit() override {
+  void PostProfileInit(Profile* profile, bool is_initial_profile) override {
+    // The setup below is intended to run for only the initial profile.
+    if (!is_initial_profile)
+      return;
+
     connection_change_simulator_.SetConnectionType(
         network::mojom::ConnectionType::CONNECTION_WIFI);
   }
diff --git a/chrome/browser/ash/login/demo_mode/OWNERS b/chrome/browser/ash/login/demo_mode/OWNERS
index f8073eb..ec03501e 100644
--- a/chrome/browser/ash/login/demo_mode/OWNERS
+++ b/chrome/browser/ash/login/demo_mode/OWNERS
@@ -2,3 +2,4 @@
 agawronska@chromium.org
 tbarzic@chromium.org
 jacksontadie@google.com
+lbowen@google.com
diff --git a/chrome/browser/ash/login/demo_mode/demo_session.cc b/chrome/browser/ash/login/demo_mode/demo_session.cc
index f4eb2b5..0b2fa29 100644
--- a/chrome/browser/ash/login/demo_mode/demo_session.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_session.cc
@@ -354,7 +354,10 @@
       chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
           chromeos::system::kRegionKey, &region_code);
   if (found_region_code) {
-    return region_code.substr(0, region_code.find("."));
+    std::string region_code_upper_case = base::ToUpperASCII(region_code);
+    std::string region_upper_case =
+        region_code_upper_case.substr(0, region_code_upper_case.find("."));
+    return region_upper_case.length() == 2 ? region_upper_case : "";
   }
   return "";
 }
diff --git a/chrome/browser/ash/login/demo_mode/demo_session.h b/chrome/browser/ash/login/demo_mode/demo_session.h
index 18789c4..f02cc2c 100644
--- a/chrome/browser/ash/login/demo_mode/demo_session.h
+++ b/chrome/browser/ash/login/demo_mode/demo_session.h
@@ -76,8 +76,8 @@
   // TODO(crbug.com/983359): Sort these by country name in the current locale
   // instead of using this hard-coded US-centric order.
   static constexpr char kSupportedCountries[][3] = {
-      "us", "be", "ca", "dk", "fi", "fr", "de", "ie",
-      "it", "jp", "lu", "nl", "no", "es", "se", "gb"};
+      "US", "BE", "CA", "DK", "FI", "FR", "DE", "IE",
+      "IT", "JP", "LU", "NL", "NO", "ES", "SE", "GB"};
 
   static constexpr char kCountryNotSelectedId[] = "N/A";
 
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
index 973ed5e..51cc3d5 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
@@ -384,29 +384,29 @@
   // Verify the country names are displayed correctly. Regression test for
   // potential country code changes.
   const base::flat_map<std::string, std::string> kCountryCodeToNameMap = {
-      {"us", "United States"},
-      {"be", "Belgium"},
-      {"ca", "Canada"},
-      {"dk", "Denmark"},
-      {"fi", "Finland"},
-      {"fr", "France"},
-      {"de", "Germany"},
-      {"ie", "Ireland"},
-      {"it", "Italy"},
-      {"jp", "Japan"},
-      {"lu", "Luxembourg"},
-      {"nl", "Netherlands"},
-      {"no", "Norway"},
-      {"es", "Spain"},
-      {"se", "Sweden"},
-      {"gb", "United Kingdom"},
+      {"US", "United States"},
+      {"BE", "Belgium"},
+      {"CA", "Canada"},
+      {"DK", "Denmark"},
+      {"FI", "Finland"},
+      {"FR", "France"},
+      {"DE", "Germany"},
+      {"IE", "Ireland"},
+      {"IT", "Italy"},
+      {"JP", "Japan"},
+      {"LU", "Luxembourg"},
+      {"NL", "Netherlands"},
+      {"NO", "Norway"},
+      {"ES", "Spain"},
+      {"SE", "Sweden"},
+      {"GB", "United Kingdom"},
       {"N/A", "Please select a country"}};
 
   system::ScopedFakeStatisticsProvider statistics_provider_;
 
   void SelectFranceAndFinishSetup() {
     // Select France as the Demo Mode country.
-    test::OobeJS().SelectElementInPath("fr", kDemoPreferencesCountrySelect);
+    test::OobeJS().SelectElementInPath("FR", kDemoPreferencesCountrySelect);
     test::OobeJS().ExpectEnabledPath(kDemoPreferencesNext);
     test::OobeJS().ClickOnPath(kDemoPreferencesNext);
 
@@ -546,9 +546,9 @@
     EXPECT_EQ(it->second, test::OobeJS().GetString(query));
   }
 
-  // Expect active "OK" button with "us" selected as country.
+  // Expect active "OK" button with "US" selected as country.
   test::OobeJS().ExpectEnabledPath(kDemoPreferencesNext);
-  test::OobeJS().ExpectElementValue("us", kDemoPreferencesCountrySelect);
+  test::OobeJS().ExpectElementValue("US", kDemoPreferencesCountrySelect);
 
   SelectFranceAndFinishSetup();
 }
@@ -1252,7 +1252,7 @@
 
   // Expect active "OK" button when entering the preference screen.
   test::OobeJS().ExpectEnabledPath(kDemoPreferencesNext);
-  test::OobeJS().ExpectElementValue("ca", kDemoPreferencesCountrySelect);
+  test::OobeJS().ExpectElementValue("CA", kDemoPreferencesCountrySelect);
   test::OobeJS().ClickOnPath(kDemoPreferencesNext);
 
   UseOnlineModeOnNetworkScreen();
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_controller.cc b/chrome/browser/ash/login/demo_mode/demo_setup_controller.cc
index 984d446..0c10387 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_controller.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_controller.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ash/login/demo_mode/demo_setup_controller.h"
 
+#include <algorithm>
+#include <cctype>
 #include <utility>
 
 #include "ash/components/arc/arc_util.h"
@@ -500,12 +502,16 @@
   const std::string country =
       g_browser_process->local_state()->GetString(prefs::kDemoModeCountry);
 
+  std::string country_uppercase = base::ToUpperASCII(country);
+  std::string country_lowercase = base::ToLowerASCII(country);
+
   // Exclude US as it is the default country.
-  if (country != "us" &&
+  if (country_uppercase != "US" &&
       std::find(std::begin(DemoSession::kSupportedCountries),
                 std::end(DemoSession::kSupportedCountries),
-                country) != std::end(DemoSession::kSupportedCountries)) {
-    return "admin-" + country + "@" + policy::kDemoModeDomain;
+                country_uppercase) !=
+          std::end(DemoSession::kSupportedCountries)) {
+    return "admin-" + country_lowercase + "@" + policy::kDemoModeDomain;
   }
   return std::string();
 }
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_controller_unittest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_controller_unittest.cc
index a35e056..273cf65f 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_controller_unittest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_controller_unittest.cc
@@ -399,22 +399,32 @@
 TEST_F(DemoSetupControllerTest, GetSubOrganizationEmail) {
   std::string email = DemoSetupController::GetSubOrganizationEmail();
 
-  // kDemoModeCountry defaults to "us" which is the root organisation.
+  // kDemoModeCountry defaults to "US" which is the root organisation.
   EXPECT_EQ(email, "");
 
   // Test other supported countries.
-  const std::string testing_supported_countries[] = {"be", "de", "es", "fr",
-                                                     "ie", "jp", "nl", "se"};
+  const std::string testing_supported_countries[] = {
+      "BE", "CA", "DK", "FI", "FR", "DE", "IE", "IT",
+      "JP", "LU", "NL", "NO", "ES", "SE", "GB"};
 
   for (auto country : testing_supported_countries) {
     g_browser_process->local_state()->SetString(prefs::kDemoModeCountry,
                                                 country);
     email = DemoSetupController::GetSubOrganizationEmail();
-    EXPECT_EQ(email, "admin-" + country + "@" + policy::kDemoModeDomain);
+
+    std::string country_lowercase = base::ToLowerASCII(country);
+    EXPECT_EQ(email,
+              "admin-" + country_lowercase + "@" + policy::kDemoModeDomain);
   }
 
   // Test unsupported country string.
-  g_browser_process->local_state()->SetString(prefs::kDemoModeCountry, "kr");
+  g_browser_process->local_state()->SetString(prefs::kDemoModeCountry, "KR");
+  email = DemoSetupController::GetSubOrganizationEmail();
+  EXPECT_EQ(email, "");
+
+  // Test unsupported region string.
+  g_browser_process->local_state()->SetString(prefs::kDemoModeCountry,
+                                              "NORDIC");
   email = DemoSetupController::GetSubOrganizationEmail();
   EXPECT_EQ(email, "");
 
@@ -424,5 +434,30 @@
   EXPECT_EQ(email, "");
 }
 
+TEST_F(DemoSetupControllerTest, GetSubOrganizationEmailWithLowercase) {
+  std::string email = DemoSetupController::GetSubOrganizationEmail();
+
+  // kDemoModeCountry defaults to "US" which is the root organisation.
+  EXPECT_EQ(email, "");
+
+  // Test other supported countries.
+  const std::string testing_supported_countries[] = {
+      "be", "ca", "dk", "fi", "fr", "de", "ie", "it",
+      "jp", "lu", "nl", "no", "es", "se", "gb"};
+
+  for (auto country : testing_supported_countries) {
+    g_browser_process->local_state()->SetString(prefs::kDemoModeCountry,
+                                                country);
+    email = DemoSetupController::GetSubOrganizationEmail();
+
+    EXPECT_EQ(email, "admin-" + country + "@" + policy::kDemoModeDomain);
+  }
+
+  // Test unsupported country string.
+  g_browser_process->local_state()->SetString(prefs::kDemoModeCountry, "kr");
+  email = DemoSetupController::GetSubOrganizationEmail();
+  EXPECT_EQ(email, "");
+}
+
 }  // namespace
 }  //  namespace ash
diff --git a/chrome/browser/ash/login/oobe_interactive_ui_test.cc b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
index 93b2651..ff5b07c 100644
--- a/chrome/browser/ash/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/ash/login/oobe_interactive_ui_test.cc
@@ -470,7 +470,11 @@
   ~NativeWindowVisibilityBrowserMainExtraParts() override = default;
 
   // ChromeBrowserMainExtraParts:
-  void PostProfileInit() override {
+  void PostProfileInit(Profile* profile, bool is_initial_profile) override {
+    // The setup below is intended to run for only the initial profile.
+    if (!is_initial_profile)
+      return;
+
     gfx::NativeWindow window =
         LoginDisplayHost::default_host()->GetNativeWindow();
     if (window)
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 3169461..d7718a6 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1127,15 +1127,24 @@
   media_router::ChromeMediaRouterFactory::DoPlatformInit();
 }
 
-void ChromeBrowserMainParts::PostProfileInit() {
-  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostProfileInit");
+void ChromeBrowserMainParts::CallPostProfileInit(Profile* profile) {
+  bool is_initial_profile = !initialized_initial_profile_;
+  initialized_initial_profile_ = true;
 
-  g_browser_process->CreateDevToolsProtocolHandler();
-  if (parsed_command_line().HasSwitch(::switches::kAutoOpenDevToolsForTabs))
-    g_browser_process->CreateDevToolsAutoOpener();
+  PostProfileInit(profile, is_initial_profile);
+}
+
+void ChromeBrowserMainParts::PostProfileInit(Profile* profile,
+                                             bool is_initial_profile) {
+  if (is_initial_profile) {
+    TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostProfileInit");
+    g_browser_process->CreateDevToolsProtocolHandler();
+    if (parsed_command_line().HasSwitch(::switches::kAutoOpenDevToolsForTabs))
+      g_browser_process->CreateDevToolsAutoOpener();
+  }
 
   for (auto& chrome_extra_part : chrome_extra_parts_)
-    chrome_extra_part->PostProfileInit();
+    chrome_extra_part->PostProfileInit(profile, is_initial_profile);
 }
 
 void ChromeBrowserMainParts::PreBrowserStart() {
@@ -1476,7 +1485,7 @@
 
   // TODO(stevenjb): Move WIN and MACOSX specific code to appropriate Parts.
   // (requires supporting early exit).
-  PostProfileInit();
+  CallPostProfileInit(profile_);
 
 #if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
   // Execute first run specific code after the PrefService has been initialized
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index d28d8ae..ec13121 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -86,8 +86,11 @@
 
   // Additional stages for ChromeBrowserMainExtraParts. These stages are called
   // in order from PreMainMessageLoopRun(). See implementation for details.
+  // TODO(crbug.com/1150326): Update the comment once the feature launches.
+  // `PostProfileInit()` might not be called in order, it is planned to be
+  // called for each new profile as part of that launch. See bug for context.
   virtual void PreProfileInit();
-  virtual void PostProfileInit();
+  virtual void PostProfileInit(Profile* profile, bool is_initial_profile);
   virtual void PreBrowserStart();
   virtual void PostBrowserStart();
 
@@ -104,8 +107,6 @@
     return user_data_dir_;
   }
 
-  Profile* profile() { return profile_; }
-
  private:
   friend class ChromeBrowserMainPartsTestApi;
 
@@ -140,6 +141,10 @@
   int PreCreateThreadsImpl();
   int PreMainMessageLoopRunImpl();
 
+  // Wrapper for `PostProfileInit()` that provides to it the right
+  // `is_initial_profile` value.
+  void CallPostProfileInit(Profile* profile);
+
   // Members initialized on construction ---------------------------------------
 
   content::MainFunctionParams parameters_;
@@ -208,6 +213,10 @@
   base::FilePath user_data_dir_;
 
   raw_ptr<StartupData> startup_data_;
+
+  // Indicates that the initial profile has been created and we started
+  // executing `PostProfileInit()` for it.
+  bool initialized_initial_profile_ = false;
 };
 
 #endif  // CHROME_BROWSER_CHROME_BROWSER_MAIN_H_
diff --git a/chrome/browser/chrome_browser_main_android.cc b/chrome/browser/chrome_browser_main_android.cc
index d63e022..db28133 100644
--- a/chrome/browser/chrome_browser_main_android.cc
+++ b/chrome/browser/chrome_browser_main_android.cc
@@ -52,8 +52,12 @@
   return result_code;
 }
 
-void ChromeBrowserMainPartsAndroid::PostProfileInit() {
-  ChromeBrowserMainParts::PostProfileInit();
+void ChromeBrowserMainPartsAndroid::PostProfileInit(Profile* profile,
+                                                    bool is_initial_profile) {
+  DCHECK(is_initial_profile);  // No multiprofile on Android, only the initial
+                               // call should happen.
+
+  ChromeBrowserMainParts::PostProfileInit(profile, is_initial_profile);
 
   // Idempotent.  Needs to be called once on startup.  If
   // InitializeClipboardAndroidFromLocalState() is called multiple times (e.g.,
@@ -63,7 +67,7 @@
 
   // Start watching the preferences that need to be backed up backup using
   // Android backup, so that we create a new backup if they change.
-  backup_watcher_ = std::make_unique<android::ChromeBackupWatcher>(profile());
+  backup_watcher_ = std::make_unique<android::ChromeBackupWatcher>(profile);
 
   // The GCM driver can be used at this point because the primary profile has
   // been created. Register non-profile-specific things that use GCM so that no
diff --git a/chrome/browser/chrome_browser_main_android.h b/chrome/browser/chrome_browser_main_android.h
index da9d7b9..e5e9a08 100644
--- a/chrome/browser/chrome_browser_main_android.h
+++ b/chrome/browser/chrome_browser_main_android.h
@@ -22,7 +22,7 @@
 
   // content::BrowserMainParts overrides.
   int PreCreateThreads() override;
-  void PostProfileInit() override;
+  void PostProfileInit(Profile* profile, bool is_initial_profile) override;
   int PreEarlyInitialization() override;
   void PostEarlyInitialization() override;
 
diff --git a/chrome/browser/chrome_browser_main_extra_parts.h b/chrome/browser/chrome_browser_main_extra_parts.h
index 6b7bd073..1d1a9bd 100644
--- a/chrome/browser/chrome_browser_main_extra_parts.h
+++ b/chrome/browser/chrome_browser_main_extra_parts.h
@@ -17,6 +17,8 @@
 // Chrome toolkits (e.g., GTK, VIEWS, ASH, AURA, etc.; see
 // ChromeContentBrowserClient::CreateBrowserMainParts()).
 
+class Profile;
+
 class ChromeBrowserMainExtraParts {
  public:
   virtual ~ChromeBrowserMainExtraParts() {}
@@ -36,7 +38,7 @@
   virtual void PreCreateThreads() {}
   virtual void PostCreateThreads() {}
   virtual void PreProfileInit() {}
-  virtual void PostProfileInit() {}
+  virtual void PostProfileInit(Profile* profile, bool is_initial_profile) {}
   virtual void PreBrowserStart() {}
   virtual void PostBrowserStart() {}
   virtual void PreMainMessageLoopRun() {}
diff --git a/chrome/browser/chrome_browser_main_mac.h b/chrome/browser/chrome_browser_main_mac.h
index 0c5201eb..1650fe8 100644
--- a/chrome/browser/chrome_browser_main_mac.h
+++ b/chrome/browser/chrome_browser_main_mac.h
@@ -23,7 +23,7 @@
   void PreCreateMainMessageLoop() override;
   void PostCreateMainMessageLoop() override;
   void PreProfileInit() override;
-  void PostProfileInit() override;
+  void PostProfileInit(Profile* profile, bool is_initial_profile) override;
 
   // Perform platform-specific work that needs to be done after the main event
   // loop has ended. The embedder must be sure to call this.
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index 97afd5b..dbd8f7eb 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -154,10 +154,17 @@
   g_browser_process->platform_part()->app_shim_listener()->Init();
 }
 
-void ChromeBrowserMainPartsMac::PostProfileInit() {
-  MacStartupProfiler::GetInstance()->Profile(
-      MacStartupProfiler::POST_PROFILE_INIT);
-  ChromeBrowserMainPartsPosix::PostProfileInit();
+void ChromeBrowserMainPartsMac::PostProfileInit(Profile* profile,
+                                                bool is_initial_profile) {
+  if (is_initial_profile) {
+    MacStartupProfiler::GetInstance()->Profile(
+        MacStartupProfiler::POST_PROFILE_INIT);
+  }
+
+  ChromeBrowserMainPartsPosix::PostProfileInit(profile, is_initial_profile);
+
+  if (!is_initial_profile)
+    return;
 
   // Activation of Keystone is not automatic but done in response to the
   // counting and reporting of profiles.
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index 93a5245..a7a8373 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -636,8 +636,13 @@
                  MB_OK | MB_ICONERROR | MB_TOPMOST);
 }
 
-void ChromeBrowserMainPartsWin::PostProfileInit() {
-  ChromeBrowserMainParts::PostProfileInit();
+void ChromeBrowserMainPartsWin::PostProfileInit(Profile* profile,
+                                                bool is_initial_profile) {
+  ChromeBrowserMainParts::PostProfileInit(profile, is_initial_profile);
+
+  // The setup below is intended to run for only the initial profile.
+  if (!is_initial_profile)
+    return;
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Explicitly disable the third-party modules blocking.
@@ -671,7 +676,7 @@
           switches::kPwaLauncherVersion) != chrome::kChromeVersion) {
     content::BrowserThread::PostBestEffortTask(
         FROM_HERE, base::SequencedTaskRunnerHandle::Get(),
-        base::BindOnce(&UpdatePwaLaunchersForProfile, profile()->GetPath()));
+        base::BindOnce(&UpdatePwaLaunchersForProfile, profile->GetPath()));
   }
 }
 
diff --git a/chrome/browser/chrome_browser_main_win.h b/chrome/browser/chrome_browser_main_win.h
index 8382ae08..6a3ee00f 100644
--- a/chrome/browser/chrome_browser_main_win.h
+++ b/chrome/browser/chrome_browser_main_win.h
@@ -39,7 +39,7 @@
 
   // ChromeBrowserMainParts overrides.
   void ShowMissingLocaleMessageBox() override;
-  void PostProfileInit() override;
+  void PostProfileInit(Profile* profile, bool is_initial_profile) override;
   void PostBrowserStart() override;
 
   // Prepares the localized strings that are going to be displayed to
diff --git a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java
index 2c20ad02..e5bb70b 100644
--- a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java
+++ b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceDropNotificationManagerTest.java
@@ -163,7 +163,7 @@
 
             mPriceDropNotificationManager.createNotificationChannel();
             assertNotNull(mPriceDropNotificationManager.getNotificationChannel());
-            assertEquals(NotificationManager.IMPORTANCE_LOW,
+            assertEquals(NotificationManager.IMPORTANCE_DEFAULT,
                     mPriceDropNotificationManager.getNotificationChannel().getImportance());
 
             assertTrue(mPriceDropNotificationManager.canPostNotification());
diff --git a/chrome/browser/download/background_download_service_factory.cc b/chrome/browser/download/background_download_service_factory.cc
index f1dfb804..caa7d8f 100644
--- a/chrome/browser/download/background_download_service_factory.cc
+++ b/chrome/browser/download/background_download_service_factory.cc
@@ -48,7 +48,7 @@
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/storage_partition.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/download/android/service/download_task_scheduler.h"
 #endif
 
@@ -198,7 +198,7 @@
             {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
 
     std::unique_ptr<download::TaskScheduler> task_scheduler;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
     task_scheduler =
         std::make_unique<download::android::DownloadTaskScheduler>();
 #else
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 4e73163..6cccaa72 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -93,7 +93,7 @@
 #include "ppapi/buildflags/buildflags.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "base/android/path_utils.h"
 #include "chrome/browser/download/android/chrome_duplicate_download_infobar_delegate.h"
 #include "chrome/browser/download/android/download_controller.h"
@@ -125,7 +125,7 @@
 #include "components/offline_pages/core/client_namespace_constants.h"
 #endif
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "components/services/quarantine/public/cpp/quarantine_features_win.h"
 #endif
 
@@ -215,7 +215,7 @@
 
 // On Android, Chrome wants to warn the user of file overwrites rather than
 // uniquify.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 const DownloadPathReservationTracker::FilenameConflictAction
     kDefaultPlatformConflictAction = DownloadPathReservationTracker::PROMPT;
 #else
@@ -246,7 +246,7 @@
   }
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 // TODO(qinmin): reuse the similar function defined in
 // DownloadResourceThrottle.
 void OnDownloadAcquireFileAccessPermissionDone(
@@ -290,7 +290,7 @@
       break;
   }
 }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
 void OnCheckExistingDownloadPathDone(
     std::unique_ptr<DownloadTargetInfo> target_info,
@@ -308,7 +308,7 @@
       target_info->result);
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 // Callback used by Mixed Download infobar on Android. Unlike on Desktop, this
 // infobar's entire life occurs prior to download start.
 void HandleMixedDownloadInfoBarResult(
@@ -423,7 +423,7 @@
       next_id_retrieved_(false),
       download_prefs_(new DownloadPrefs(profile)),
       is_file_picker_showing_(false) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   download_dialog_bridge_ = std::make_unique<DownloadDialogBridge>();
 #endif
 }
@@ -444,7 +444,7 @@
   }
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 void ChromeDownloadManagerDelegate::ShowDownloadDialog(
     gfx::NativeWindow native_window,
     int64_t total_bytes,
@@ -471,7 +471,7 @@
     DownloadDialogBridge* bridge) {
   download_dialog_bridge_.reset(bridge);
 }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
 void ChromeDownloadManagerDelegate::Shutdown() {
   download_prefs_.reset();
@@ -544,7 +544,7 @@
       GetPlatformDownloadPath(profile_, download, PLATFORM_TARGET_PATH);
   DownloadPathReservationTracker::FilenameConflictAction action =
       kDefaultPlatformConflictAction;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   if (!download_path.empty())
     action = DownloadPathReservationTracker::UNIQUIFY;
 #endif
@@ -832,7 +832,7 @@
   MaybeSendDangerousDownloadOpenedReport(download,
                                          false /* show_download_in_folder */);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   DownloadUtils::OpenDownload(download, DownloadOpenSource::kUnknown);
 #else
 
@@ -995,7 +995,7 @@
 
 // TODO(xingliu): We should abstract a DownloadFilePicker interface and make all
 // platform use it.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   content::WebContents* web_contents =
       content::DownloadItemUtils::GetWebContents(download);
     if (reason == DownloadConfirmationReason::SAVE_AS) {
@@ -1160,7 +1160,7 @@
           weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 void ChromeDownloadManagerDelegate::GenerateUniqueFileNameDone(
     gfx::NativeWindow native_window,
     bool show_download_later_dialog,
@@ -1235,7 +1235,7 @@
       download && download->GetTotalBytes() >= min_file_size_kb * 1024;
   return met_file_size_condition;
 }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
 void ChromeDownloadManagerDelegate::DetermineLocalPath(
     DownloadItem* download,
@@ -1539,7 +1539,7 @@
         target_info->is_filetype_handled_safely)
       DownloadItemModel(item).SetShouldPreferOpeningInBrowser(true);
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
     if (item->GetOriginalMimeType() == "application/x-x509-user-cert")
       DownloadItemModel(item).SetShouldPreferOpeningInBrowser(true);
 #endif
@@ -1557,7 +1557,7 @@
 
   base::FilePath target_path = target_info->target_path;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   // Present a mixed content download infobar when needed, and wait to initiate
   // the download until the user decides what to do.
   // On Desktop, this is handled using the unsafe-download warnings that are
@@ -1607,8 +1607,8 @@
 
 bool ChromeDownloadManagerDelegate::IsOpenInBrowserPreferreredForFile(
     const base::FilePath& path) {
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   if (path.MatchesExtension(FILE_PATH_LITERAL(".pdf"))) {
     return !download_prefs_->ShouldOpenPdfInSystemReader();
   }
@@ -1616,7 +1616,7 @@
 
   // On Android, always prefer opening with an external app. On ChromeOS, there
   // are no external apps so just allow all opens to be handled by the "System."
-#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
     BUILDFLAG(ENABLE_PLUGINS)
   // TODO(asanka): Consider other file types and MIME types.
   // http://crbug.com/323561
@@ -1715,8 +1715,8 @@
     bool content_initiated,
     content::CheckDownloadAllowedCallback check_download_allowed_cb) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   // Don't download pdf if it is a file URL, as that might cause an infinite
   // download loop if Chrome is not the system pdf viewer.
   if (url.SchemeIsFile() && download_prefs_->ShouldOpenPdfInSystemReader()) {
@@ -1735,7 +1735,7 @@
   CanDownloadCallback cb = base::BindOnce(
       &ChromeDownloadManagerDelegate::OnCheckDownloadAllowedComplete,
       weak_ptr_factory_.GetWeakPtr(), std::move(check_download_allowed_cb));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   DownloadControllerBase::Get()->AcquireFileAccessPermission(
       web_contents_getter,
       base::BindOnce(&OnDownloadAcquireFileAccessPermissionDone,
@@ -1757,8 +1757,8 @@
 std::unique_ptr<download::DownloadItemRenameHandler>
 ChromeDownloadManagerDelegate::GetRenameHandlerForDownload(
     download::DownloadItem* download_item) {
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   return enterprise_connectors::FileSystemRenameHandler::CreateIfNeeded(
       download_item);
 #else
@@ -1773,8 +1773,8 @@
   DCHECK(download_item);
   DCHECK(download_item->IsSavePackageDownload());
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   if (!base::FeatureList::IsEnabled(
           download::features::kAllowSavePackageScanning)) {
     std::move(callback).Run(true);
@@ -1840,7 +1840,7 @@
 // static
 void ChromeDownloadManagerDelegate::ConnectToQuarantineService(
     mojo::PendingReceiver<quarantine::mojom::Quarantine> receiver) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   if (base::FeatureList::IsEnabled(quarantine::kOutOfProcessQuarantine)) {
     content::ServiceProcessHost::Launch(
         std::move(receiver), content::ServiceProcessHost::Options()
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 5dccba9..8fc853a 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -33,7 +33,7 @@
 #include "extensions/buildflags/buildflags.h"
 #include "ui/gfx/native_widget_types.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/download/android/download_dialog_bridge.h"
 #endif
 
@@ -72,7 +72,7 @@
 
   void SetDownloadManager(content::DownloadManager* dm);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   void ShowDownloadDialog(gfx::NativeWindow native_window,
                           int64_t total_bytes,
                           DownloadLocationDialogType dialog_type,
@@ -221,7 +221,7 @@
   void GetFileMimeType(const base::FilePath& path,
                        GetFileMimeTypeCallback callback) override;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   virtual void OnDownloadCanceled(download::DownloadItem* download,
                                   bool has_no_external_storage);
 #endif
@@ -289,7 +289,7 @@
   // multiple downloads are associated with the same file path.
   bool IsMostRecentDownloadItemAtFilePath(download::DownloadItem* download);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   // Called after a unique file name is generated in the case that there is a
   // TARGET_CONFLICT and the new file name should be displayed to the user.
   void GenerateUniqueFileNameDone(
@@ -306,7 +306,7 @@
 
   raw_ptr<Profile> profile_;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   std::unique_ptr<DownloadDialogBridge> download_dialog_bridge_;
 #endif
 
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index 6afb70dc..faefa5f 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -70,7 +70,7 @@
 #include "content/public/browser/plugin_service.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/download/download_prompt_status.h"
 #include "components/infobars/content/content_infobar_manager.h"
 #include "components/infobars/core/infobar.h"
@@ -175,7 +175,7 @@
         FROM_HERE, base::BindOnce(std::move(callback), result, path_to_return));
   }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   void OnDownloadCanceled(download::DownloadItem* download,
                           bool has_no_external_storage) override {}
 #endif
@@ -324,7 +324,7 @@
   pref_service_ = profile()->GetTestingPrefService();
   web_contents()->SetDelegate(&web_contents_delegate_);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   pref_service_->SetInteger(prefs::kPromptForDownloadAndroid,
                             static_cast<int>(DownloadPromptStatus::DONT_SHOW));
 
@@ -855,7 +855,7 @@
                         kInsecureDownloadHistogramTargetInsecure, histograms);
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 TEST_F(ChromeDownloadManagerDelegateTest, InterceptDownloadByOfflinePages) {
   const GURL kUrl("http://example.com/foo");
   std::string mime_type = "text/html";
@@ -1160,7 +1160,7 @@
 }
 
 // MIXEDSCRIPT content setting only applies to Desktop.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 TEST_F(ChromeDownloadManagerDelegateTest,
        BlockedAsActiveContent_PolicyOverride) {
   // Verifies that active mixed content download blocking is overridden by the
@@ -1251,7 +1251,7 @@
   }
 }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 namespace {
 // Verify the file picker confirmation result matches |expected_result|. Run
 // |completion_closure| on completion.
@@ -1652,7 +1652,7 @@
   run_loop.Run();
 }
 
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
 // TODO(crbug.com/739204) Add a Windows version of this test.
 TEST_F(ChromeDownloadManagerDelegateTestWithSafeBrowsing,
        TrustedSourcesPolicyTrusted) {
@@ -1673,7 +1673,7 @@
 #endif  // OS_WIN
 #endif  // FULL_SAFE_BROWSING
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 
 namespace {
 
diff --git a/chrome/browser/download/default_download_dir_policy_handler.cc b/chrome/browser/download/default_download_dir_policy_handler.cc
index 61a269d..d414847 100644
--- a/chrome/browser/download/default_download_dir_policy_handler.cc
+++ b/chrome/browser/download/default_download_dir_policy_handler.cc
@@ -37,7 +37,7 @@
     return;
   std::string str_value = value->GetString();
   base::FilePath::StringType string_value =
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
       base::UTF8ToWide(str_value);
 #else
       str_value;
@@ -47,7 +47,7 @@
       download_dir_util::ExpandDownloadDirectoryPath(string_value, parameters);
 
   if (policies.Get(policy_name())->level == policy::POLICY_LEVEL_RECOMMENDED) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
     prefs->SetValue(prefs::kDownloadDefaultDirectory,
                     base::Value(base::WideToUTF8(expanded_value)));
     prefs->SetValue(prefs::kSaveFileDefaultDirectory,
diff --git a/chrome/browser/download/deferred_client_wrapper.cc b/chrome/browser/download/deferred_client_wrapper.cc
index 09f3b288c..d07eedb 100644
--- a/chrome/browser/download/deferred_client_wrapper.cc
+++ b/chrome/browser/download/deferred_client_wrapper.cc
@@ -21,14 +21,14 @@
 DeferredClientWrapper::DeferredClientWrapper(ClientFactory client_factory,
                                              SimpleFactoryKey* key)
     : client_factory_(std::move(client_factory)), key_(key) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   full_browser_requested_ = false;
 #endif
 
   FullBrowserTransitionManager::Get()->RegisterCallbackOnProfileCreation(
       key_, base::BindOnce(&DeferredClientWrapper::InflateClient,
                            weak_ptr_factory_.GetWeakPtr()));
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
   // On non-android platforms we can only be running in full browser mode. In
   // full browser mode, FullBrowserTransitionManager synchronously calls the
   // callback when it is registered.
@@ -174,7 +174,7 @@
   if (wrapped_client_) {
     DoRunDeferredClosures();
   } else if (force_inflate) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
     // The constructor registers InflateClient as a callback with
     // FullBrowserTransitionManager on Profile creation. We just need to trigger
     // loading full browser. Once full browser is loaded and  profile is
@@ -203,7 +203,7 @@
   DoRunDeferredClosures();
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 void DeferredClientWrapper::LaunchFullBrowser() {
   if (full_browser_requested_)
     return;
diff --git a/chrome/browser/download/deferred_client_wrapper.h b/chrome/browser/download/deferred_client_wrapper.h
index c6ea219..5c2157e1 100644
--- a/chrome/browser/download/deferred_client_wrapper.h
+++ b/chrome/browser/download/deferred_client_wrapper.h
@@ -83,7 +83,7 @@
   ClientFactory client_factory_;
   raw_ptr<SimpleFactoryKey> key_;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   // This is needed to record UMA for when DownloadClientWrapper requests a full
   // browser start while the browser is running in reduced mode. Reduced mode is
   // only on Android so it is ifdefed out on other platforms to prevent the
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index d483835..3e1f2f43 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -431,7 +431,7 @@
   return item->GetFileExternallyRemoved();
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS)
 // Called when a download starts. Marks the download as hidden.
 void SetHiddenDownloadCallback(DownloadItem* item,
                                download::DownloadInterruptReason reason) {
@@ -1479,7 +1479,7 @@
   CheckDownload(browser(), file, file);
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 // Download a file and confirm that the file is correctly quarantined.
 //
 // TODO(asanka): We should enable the test on Mac as well, but currently
@@ -2275,7 +2275,7 @@
   return std::move(response);
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 // https://crbug.com/788160
 #define MAYBE_DownloadHistoryCheck DISABLED_DownloadHistoryCheck
 #else
@@ -3288,8 +3288,8 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH) && \
     (!defined(NDEBUG) || defined(MEMORY_SANITIZER))
 #define MAYBE_SaveLargeImage DISABLED_SaveLargeImage
-#elif defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
-    defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS)
 // Flaking on Windows, macOS, Linux, ChromeOS. https://crbug.com/1141263
 #define MAYBE_SaveLargeImage DISABLED_SaveLargeImage
 #else
@@ -3448,7 +3448,7 @@
 }
 
 // TODO(crbug.com/1249757): Flaky on Windows 7.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define MAYBE_DownloadErrorsServer DISABLED_DownloadErrorsServer
 #else
 #define MAYBE_DownloadErrorsServer DownloadErrorsServer
@@ -3499,7 +3499,7 @@
   DownloadFilesCheckErrors(base::size(download_info), download_info);
 }
 
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
 // https://crbug.com/739766
 #define MAYBE_DownloadErrorsFile DISABLED_DownloadErrorsFile
 #else
@@ -3632,7 +3632,7 @@
 // Test that we show a dangerous downloads warning for a dangerous file
 // downloaded through a blob: URL.
 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadDangerousBlobData) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // On Windows, if SafeBrowsing is enabled, certain file types (.exe, .cab,
   // .msi) will be handled by the DownloadProtectionService. However, if the URL
   // is non-standard (e.g. blob:) then those files won't be handled by the
@@ -3692,7 +3692,7 @@
 }
 
 // TODO(https://crbug.com/1244128): Flaky on Win7
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define MAYBE_AltClickDownloadReferrerPolicy \
   DISABLED_AltClickDownloadReferrerPolicy
 #else
@@ -3773,7 +3773,7 @@
 }
 
 // TODO(https://crbug.com/1244128): Flaky on Win7
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define MAYBE_SaveLinkAsReferrerPolicy DISABLED_SaveLinkAsReferrerPolicy
 #else
 #define MAYBE_SaveLinkAsReferrerPolicy SaveLinkAsReferrerPolicy
@@ -3859,7 +3859,7 @@
 
 // TODO(https://crbug.com/1244128): Flaky on Win7
 // TODO(crbug.com/1269422): Flaky on Lacros
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_SaveLinkAsVsCrossOriginResourcePolicy \
   DISABLED_SaveLinkAsVsCrossOriginResourcePolicy
 #else
@@ -4018,7 +4018,7 @@
 }
 
 // TODO(https://crbug.com/1244128): Flaky on Win7
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define MAYBE_DownloadCrossDomainReferrerPolicy \
   DISABLED_DownloadCrossDomainReferrerPolicy
 #else
@@ -4291,7 +4291,7 @@
 
 // Test that the entire download pipeline handles unicode correctly.
 // Disabled on Windows due to flaky timeouts: crbug.com/446695
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define MAYBE_DownloadTest_CrazyFilenames DISABLED_DownloadTest_CrazyFilenames
 #else
 #define MAYBE_DownloadTest_CrazyFilenames DownloadTest_CrazyFilenames
@@ -4333,9 +4333,9 @@
     const wchar_t* const crazy_w = kCrazyFilenames[index];
     ASSERT_TRUE(base::WideToUTF8(crazy_w, wcslen(crazy_w), &crazy8));
     base::FilePath file_path(origin_directory.Append(
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
         crazy_w
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
         crazy8
 #endif
         ));
@@ -4406,7 +4406,7 @@
 // quarantining files on Mac because it is not a cocoa app.
 // TODO(benjhayden) test the equivalents on other platforms.
 
-#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
+#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
     defined(ARCH_CPU_ARM_FAMILY)
 // Timing out on ARM linux: http://crbug.com/238459
 #define MAYBE_DownloadTest_PercentComplete DISABLED_DownloadTest_PercentComplete
@@ -5197,9 +5197,9 @@
   bool final_state_seen_;
 };
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 const char kDangerousMockFilePath[] = "/downloads/dangerous/dangerous.exe";
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
 const char kDangerousMockFilePath[] = "/downloads/dangerous/dangerous.sh";
 #endif
 
@@ -5485,7 +5485,7 @@
 
 // The rest of these tests rely on the download shelf, which ChromeOS doesn't
 // use.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS)
 // Test that the download shelf is shown by starting a download.
 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadAndWait) {
   embedded_test_server()->ServeFilesFromDirectory(GetTestDataDirectory());
@@ -5753,4 +5753,4 @@
   // Download shelf should close.
   EXPECT_FALSE(browser()->window()->IsDownloadShelfVisible());
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/download/download_commands.cc b/chrome/browser/download/download_commands.cc
index e45b62e7..f6c7fb8c 100644
--- a/chrome/browser/download/download_commands.cc
+++ b/chrome/browser/download/download_commands.cc
@@ -26,14 +26,14 @@
 #include "net/base/url_util.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC) || BUILDFLAG(IS_FUCHSIA)
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
 #endif
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "chrome/browser/download/download_target_determiner.h"
 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
 #endif
@@ -167,8 +167,8 @@
   model_->ExecuteCommand(this, command);
 }
 
-#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
-    defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
 
 Browser* DownloadCommands::GetBrowser() const {
   if (!model_)
@@ -188,7 +188,7 @@
 }
 
 bool DownloadCommands::CanOpenPdfInSystemViewer() const {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   bool is_adobe_pdf_reader_up_to_date = false;
   if (IsDownloadPdf() && IsAdobeReaderDefaultPDFViewer()) {
     is_adobe_pdf_reader_up_to_date =
@@ -197,13 +197,13 @@
   return IsDownloadPdf() &&
          (IsAdobeReaderDefaultPDFViewer() ? is_adobe_pdf_reader_up_to_date
                                           : true);
-#else  // defined(OS_WIN)
+#else  // BUILDFLAG(IS_WIN)
   return IsDownloadPdf();
 #endif
 }
 
-#endif  // defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) ||
-        // defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
+        // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
 
 void DownloadCommands::CopyFileAsImageToClipboard() {
   if (!model_)
diff --git a/chrome/browser/download/download_commands.h b/chrome/browser/download/download_commands.h
index 03d40cd..b3aa05e6 100644
--- a/chrome/browser/download/download_commands.h
+++ b/chrome/browser/download/download_commands.h
@@ -11,7 +11,7 @@
 #include "content/public/browser/page_navigator.h"
 #include "ui/gfx/image/image.h"
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 class Browser;
 #endif
 
@@ -53,8 +53,8 @@
   bool IsCommandVisible(Command command) const;
   void ExecuteCommand(Command command);
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC) || BUILDFLAG(IS_FUCHSIA)
   bool IsDownloadPdf() const;
   bool CanOpenPdfInSystemViewer() const;
   Browser* GetBrowser() const;
diff --git a/chrome/browser/download/download_confirmation_result.h b/chrome/browser/download/download_confirmation_result.h
index 7b92014..633199e 100644
--- a/chrome/browser/download/download_confirmation_result.h
+++ b/chrome/browser/download/download_confirmation_result.h
@@ -26,7 +26,7 @@
   // downloaded.
   CONTINUE_WITHOUT_CONFIRMATION,
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   // After the user confirmed the file path on the dialog, we still need to
   // check to make sure the path is valid. This is only used in the Android
   // case because there is no equivalent DownloadLocationPicker to handle
diff --git a/chrome/browser/download/download_core_service_impl.cc b/chrome/browser/download/download_core_service_impl.cc
index e5993815..3eb0cc1 100644
--- a/chrome/browser/download/download_core_service_impl.cc
+++ b/chrome/browser/download/download_core_service_impl.cc
@@ -28,7 +28,7 @@
 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/download/android/download_utils.h"
 #endif
 
@@ -81,7 +81,7 @@
   download_ui_ = std::make_unique<DownloadUIController>(
       manager, std::unique_ptr<DownloadUIController::Delegate>());
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
   download_shelf_controller_ =
       std::make_unique<DownloadShelfController>(profile_);
 #endif
@@ -150,7 +150,7 @@
 }
 
 bool DownloadCoreServiceImpl::IsShelfEnabled() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   return true;
 #else
   return !extension_event_router_ || extension_event_router_->IsShelfEnabled();
diff --git a/chrome/browser/download/download_core_service_impl.h b/chrome/browser/download/download_core_service_impl.h
index 6754a2fb..f837621 100644
--- a/chrome/browser/download/download_core_service_impl.h
+++ b/chrome/browser/download/download_core_service_impl.h
@@ -13,7 +13,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "extensions/buildflags/buildflags.h"
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/download/download_shelf_controller.h"
 #endif
 
@@ -77,7 +77,7 @@
   // should be destroyed before the latter.
   std::unique_ptr<DownloadUIController> download_ui_;
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
   std::unique_ptr<DownloadShelfController> download_shelf_controller_;
 #endif
 
diff --git a/chrome/browser/download/download_danger_prompt_browsertest.cc b/chrome/browser/download/download_danger_prompt_browsertest.cc
index 37df0c8..5f7e72d 100644
--- a/chrome/browser/download/download_danger_prompt_browsertest.cc
+++ b/chrome/browser/download/download_danger_prompt_browsertest.cc
@@ -183,7 +183,7 @@
 };
 
 // Disabled for flaky timeouts on Windows. crbug.com/446696
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define MAYBE_TestAll DISABLED_TestAll
 #else
 #define MAYBE_TestAll TestAll
diff --git a/chrome/browser/download/download_dir_policy_handler.cc b/chrome/browser/download/download_dir_policy_handler.cc
index f94d65a4f..816f98c 100644
--- a/chrome/browser/download/download_dir_policy_handler.cc
+++ b/chrome/browser/download/download_dir_policy_handler.cc
@@ -39,7 +39,7 @@
   if (!CheckAndGetValue(policies, errors, &value))
     return false;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
   // Download directory can only be set as a user policy. If it is set through
   // platform policy for a chromeos=1 build, ignore it.
   if (value &&
@@ -61,7 +61,7 @@
     return;
   std::string str_value = value->GetString();
   base::FilePath::StringType string_value =
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
       base::UTF8ToWide(str_value);
 #else
       str_value;
@@ -77,7 +77,7 @@
     expanded_value = policy::path_parser::ExpandPathVariables(
         DownloadPrefs::GetDefaultDownloadDirectory().value());
   }
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   prefs->SetValue(prefs::kDownloadDefaultDirectory,
                   base::Value(base::WideToUTF8(expanded_value)));
 #else
diff --git a/chrome/browser/download/download_dir_policy_handler_unittest.cc b/chrome/browser/download/download_dir_policy_handler_unittest.cc
index 460dc8f..3e8021c 100644
--- a/chrome/browser/download/download_dir_policy_handler_unittest.cc
+++ b/chrome/browser/download/download_dir_policy_handler_unittest.cc
@@ -28,7 +28,7 @@
 
 const char* kUserIDHash = "deadbeef";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 const char* kRelativeToDriveRoot = "/home/";
 #endif
 
@@ -71,7 +71,7 @@
   EXPECT_FALSE(value->GetBool());
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 TEST_F(DownloadDirPolicyHandlerTest, SetDownloadToDrive) {
   EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
 
diff --git a/chrome/browser/download/download_dir_util.cc b/chrome/browser/download/download_dir_util.cc
index a42157d..05ba0f1 100644
--- a/chrome/browser/download/download_dir_util.cc
+++ b/chrome/browser/download/download_dir_util.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/download/download_dir_util.h"
 
 #include "base/files/file_path.h"
+#include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/policy/policy_path_parser.h"
 #include "components/policy/core/browser/configuration_policy_handler_parameters.h"
@@ -16,16 +17,16 @@
 #endif
 
 namespace {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 // Drive root folder relative to its mount point.
 const base::FilePath::CharType* kRootRelativeToDriveMount =
     FILE_PATH_LITERAL("root");
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 }  // namespace
 
 namespace download_dir_util {
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 const char kDriveNamePolicyVariableName[] = "${google_drive}";
 
 bool DownloadToDrive(const base::FilePath::StringType& string_value,
@@ -62,7 +63,7 @@
       position, strlen(kDriveNamePolicyVariableName), google_drive_root));
   return true;
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 base::FilePath::StringType ExpandDownloadDirectoryPath(
     const base::FilePath::StringType& string_value,
diff --git a/chrome/browser/download/download_dir_util.h b/chrome/browser/download/download_dir_util.h
index 2937262..f622ddd 100644
--- a/chrome/browser/download/download_dir_util.h
+++ b/chrome/browser/download/download_dir_util.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_DIR_UTIL_H_
 
 #include "base/files/file_path.h"
+#include "build/build_config.h"
 
 class Profile;
 
@@ -15,7 +16,7 @@
 
 namespace download_dir_util {
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 extern const char kDriveNamePolicyVariableName[];
 
 // Returns whether |string_value| points to a directory in Drive or not.
@@ -28,7 +29,7 @@
 bool ExpandDrivePolicyVariable(Profile* profile,
                                const base::FilePath& old_path,
                                base::FilePath* new_path);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 // Expands path variables in the download directory path |string_value|.
 base::FilePath::StringType ExpandDownloadDirectoryPath(
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index c38db06..bdb4c45 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -49,7 +49,7 @@
 #include "ui/base/l10n/time_format.h"
 #include "ui/base/text/bytes_formatting.h"
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/ui/browser.h"
 #endif
 
@@ -579,7 +579,7 @@
   RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM);
 }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 bool DownloadItemModel::IsCommandEnabled(
     const DownloadCommands* download_commands,
     DownloadCommands::Command command) const {
@@ -635,8 +635,8 @@
       return download_->GetOpenWhenComplete() ||
              download_crx_util::IsExtensionDownload(*download_);
     case DownloadCommands::ALWAYS_OPEN_TYPE:
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
       if (download_commands->CanOpenPdfInSystemViewer()) {
         DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(profile());
         return prefs->ShouldOpenPdfInSystemReader();
@@ -676,8 +676,8 @@
       bool is_checked = IsCommandChecked(download_commands,
                                          DownloadCommands::ALWAYS_OPEN_TYPE);
       DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(profile());
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
       if (download_commands->CanOpenPdfInSystemViewer()) {
         prefs->SetShouldOpenPdfInSystemReader(!is_checked);
         SetShouldPreferOpeningInBrowser(is_checked);
diff --git a/chrome/browser/download/download_item_model.h b/chrome/browser/download/download_item_model.h
index 2a25f23..8585408 100644
--- a/chrome/browser/download/download_item_model.h
+++ b/chrome/browser/download/download_item_model.h
@@ -92,7 +92,7 @@
   bool HasUserGesture() const override;
   offline_items_collection::FailState GetLastFailState() const override;
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
   bool IsCommandEnabled(const DownloadCommands* download_commands,
                         DownloadCommands::Command command) const override;
   bool IsCommandChecked(const DownloadCommands* download_commands,
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc
index 7f29fd9d..50fa8d5 100644
--- a/chrome/browser/download/download_item_model_unittest.cc
+++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -403,9 +403,9 @@
   SetupCompletedDownloadItem();
 
   EXPECT_TRUE(model().GetStatusText().empty());
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
   EXPECT_EQ("Show in Finder", base::UTF16ToUTF8(model().GetShowInFolderText()));
-#else  // defined(OS_MAC)
+#else  // BUILDFLAG(IS_MAC)
   EXPECT_EQ("Show in folder", base::UTF16ToUTF8(model().GetShowInFolderText()));
 #endif
 
diff --git a/chrome/browser/download/download_manager_utils.cc b/chrome/browser/download/download_manager_utils.cc
index 2ff67de..f3ee7a3 100644
--- a/chrome/browser/download/download_manager_utils.cc
+++ b/chrome/browser/download/download_manager_utils.cc
@@ -24,7 +24,7 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/device/public/mojom/wake_lock_provider.mojom.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "base/android/path_utils.h"
 #include "chrome/browser/download/android/download_controller.h"
 #include "chrome/browser/download/android/download_manager_service.h"
@@ -88,7 +88,7 @@
 
 // static
 void DownloadManagerUtils::InitializeSimpleDownloadManager(ProfileKey* key) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   if (!g_browser_process) {
     GetInProgressDownloadManager(key);
     return;
@@ -125,7 +125,7 @@
     scoped_refptr<network::SharedURLLoaderFactory> factory =
         SystemNetworkContextManager::GetInstance()->GetSharedURLLoaderFactory();
     in_progress_manager->set_url_loader_factory(std::move(factory));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
     in_progress_manager->set_download_start_observer(
         DownloadControllerBase::Get());
     in_progress_manager->set_intermediate_path_cb(
@@ -133,7 +133,7 @@
     base::FilePath download_dir;
     base::android::GetDownloadsDirectory(&download_dir);
     in_progress_manager->set_default_download_dir(download_dir);
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
     auto* download_provider =
         DownloadOfflineContentProviderFactory::GetForKey(key);
     download_provider->SetSimpleDownloadManagerCoordinator(coordinator);
diff --git a/chrome/browser/download/download_offline_content_provider.cc b/chrome/browser/download/download_offline_content_provider.cc
index 61bd633..5b2185ce 100644
--- a/chrome/browser/download/download_offline_content_provider.cc
+++ b/chrome/browser/download/download_offline_content_provider.cc
@@ -26,7 +26,7 @@
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "base/android/build_info.h"
 #include "chrome/browser/download/android/download_manager_bridge.h"
 #include "chrome/browser/download/android/download_manager_service.h"
@@ -52,7 +52,7 @@
 const base::TimeDelta kCheckExternallyRemovedDownloadsDelay =
     base::Milliseconds(100);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 // Invalid system download Id.
 const int kInvalidSystemDownloadId = -1;
 #endif
@@ -65,7 +65,7 @@
 std::unique_ptr<OfflineItemShareInfo> CreateShareInfo(
     const DownloadItem* item) {
   auto share_info = std::make_unique<OfflineItemShareInfo>();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   if (item) {
     share_info->uri =
         DownloadUtils::GetUriStringForPath(item->GetTargetFilePath());
@@ -145,7 +145,7 @@
       state_(State::UNINITIALIZED),
       profile_(nullptr) {
   aggregator_->RegisterProvider(name_space_, this);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   all_download_observer_ = std::make_unique<AllDownloadObserver>(this);
 #endif
 }
@@ -396,7 +396,7 @@
           &DownloadOfflineContentProvider::OnRenameDownloadCallbackDone,
           weak_ptr_factory_.GetWeakPtr(), std::move(callback), item);
   base::FilePath::StringType filename;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   filename = base::UTF8ToWide(name);
 #else
   filename = name;
@@ -495,7 +495,7 @@
   if (!ShouldShowDownloadItem(item))
     return;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   DownloadManagerBridge::RemoveCompletedDownload(item);
 #endif
 
@@ -508,7 +508,7 @@
 }
 
 void DownloadOfflineContentProvider::AddCompletedDownload(DownloadItem* item) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   base::OnceCallback<void(int64_t)> cb =
       base::BindOnce(&DownloadOfflineContentProvider::AddCompletedDownloadDone,
                      weak_ptr_factory_.GetWeakPtr(), item->GetGuid());
@@ -525,7 +525,7 @@
 void DownloadOfflineContentProvider::AddCompletedDownloadDone(
     const std::string& download_guid,
     int64_t system_download_id) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   DownloadItem* item = GetDownload(download_guid);
   if (!item)
     return;
@@ -563,7 +563,7 @@
 
   checked_for_externally_removed_downloads_ = true;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   manager_->CheckForExternallyRemovedDownloads();
 #endif
 }
diff --git a/chrome/browser/download/download_permission_request.cc b/chrome/browser/download/download_permission_request.cc
index 95def5be..1fdbc1c 100644
--- a/chrome/browser/download/download_permission_request.cc
+++ b/chrome/browser/download/download_permission_request.cc
@@ -9,7 +9,7 @@
 #include "components/permissions/request_type.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/android/android_theme_resources.h"
 #include "components/url_formatter/elide_url.h"
 #include "url/origin.h"
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc
index 9182051d..dbfae7b5 100644
--- a/chrome/browser/download/download_prefs.cc
+++ b/chrome/browser/download/download_prefs.cc
@@ -56,7 +56,7 @@
 #include "chrome/common/chrome_paths_lacros.h"
 #endif
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
 #endif
 
@@ -70,14 +70,14 @@
 // Consider downloads 'dangerous' if they go to the home directory on Linux and
 // to the desktop on any platform.
 bool DownloadPathIsDangerous(const base::FilePath& download_path) {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   base::FilePath home_dir = base::GetHomeDir();
   if (download_path == home_dir) {
     return true;
   }
 #endif
 
-#if defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
   // Neither Fuchsia nor Android have a desktop dir.
   return false;
 #else
@@ -91,7 +91,7 @@
 }
 
 base::FilePath::StringType StringToFilePathString(const std::string& src) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   return base::UTF8ToWide(src);
 #else
   return src;
@@ -167,8 +167,8 @@
                                 GetDefaultDownloadDirectoryForProfile()));
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   should_open_pdf_in_system_reader_ =
       prefs->GetBoolean(prefs::kOpenPdfDownloadInSystemReader);
 #endif
@@ -192,7 +192,7 @@
   }
 
   prompt_for_download_.Init(prefs::kPromptForDownload, prefs);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   prompt_for_download_android_.Init(prefs::kPromptForDownloadAndroid, prefs);
   RecordDownloadPromptStatus(
       static_cast<DownloadPromptStatus>(*prompt_for_download_android_));
@@ -286,11 +286,11 @@
                                  default_download_path);
   registry->RegisterFilePathPref(prefs::kSaveFileDefaultDirectory,
                                  default_download_path);
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   registry->RegisterBooleanPref(prefs::kOpenPdfDownloadInSystemReader, false);
 #endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   DownloadPromptStatus download_prompt_status =
       DownloadPromptStatus::SHOW_INITIAL;
 
@@ -376,7 +376,7 @@
   DCHECK(!download_path_.IsManaged() || !prompt_for_download_.GetValue());
 
 // Return the Android prompt for download only.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   // Use |prompt_for_download_| preference for enterprise policy.
   if (prompt_for_download_.IsManaged())
     return prompt_for_download_.GetValue();
@@ -391,7 +391,7 @@
 }
 
 bool DownloadPrefs::PromptDownloadLater() const {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   if (prompt_for_download_.IsManaged())
     return false;
 
@@ -405,7 +405,7 @@
 }
 
 bool DownloadPrefs::HasDownloadLaterPromptShown() const {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   if (base::FeatureList::IsEnabled(download::features::kDownloadLater)) {
     return *prompt_for_download_later_ !=
            static_cast<int>(DownloadLaterPromptStatus::kShowInitial);
@@ -420,8 +420,8 @@
 }
 
 bool DownloadPrefs::IsAutoOpenByUserUsed() const {
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   if (ShouldOpenPdfInSystemReader())
     return true;
 #endif
@@ -435,8 +435,8 @@
     return false;
   DCHECK(extension[0] == base::FilePath::kExtensionSeparator);
   extension.erase(0, 1);
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   if (base::FilePath::CompareEqualIgnoreCase(extension,
                                              FILE_PATH_LITERAL("pdf")) &&
       ShouldOpenPdfInSystemReader())
@@ -490,8 +490,8 @@
   SaveAutoOpenState();
 }
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
 void DownloadPrefs::SetShouldOpenPdfInSystemReader(bool should_open) {
   if (should_open_pdf_in_system_reader_ == should_open)
     return;
@@ -501,7 +501,7 @@
 }
 
 bool DownloadPrefs::ShouldOpenPdfInSystemReader() const {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   if (IsAdobeReaderDefaultPDFViewer() &&
       !DownloadTargetDeterminer::IsAdobeReaderUpToDate()) {
       return false;
@@ -512,8 +512,8 @@
 #endif
 
 void DownloadPrefs::ResetAutoOpenByUser() {
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   SetShouldOpenPdfInSystemReader(false);
 #endif
   auto_open_by_user_.clear();
@@ -527,10 +527,10 @@
 void DownloadPrefs::SaveAutoOpenState() {
   std::string extensions;
   for (auto it : auto_open_by_user_) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
     // TODO(phajdan.jr): Why we're using Sys conversion here, but not in ctor?
     std::string this_extension = base::SysWideToUTF8(it);
-#else  // defined(OS_WIN)
+#else  // BUILDFLAG(IS_WIN)
     std::string this_extension = it;
 #endif
     extensions += this_extension + ":";
diff --git a/chrome/browser/download/download_prefs.h b/chrome/browser/download/download_prefs.h
index 939cd72..87eb569 100644
--- a/chrome/browser/download/download_prefs.h
+++ b/chrome/browser/download/download_prefs.h
@@ -121,8 +121,8 @@
   // Disables auto-open based on file extension.
   void DisableAutoOpenByUserBasedOnExtension(const base::FilePath& file_name);
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   // Store the user preference to disk. If |should_open| is true, also disable
   // the built-in PDF plugin. If |should_open| is false, enable the PDF plugin.
   void SetShouldOpenPdfInSystemReader(bool should_open);
@@ -152,7 +152,7 @@
   raw_ptr<Profile> profile_;
 
   BooleanPrefMember prompt_for_download_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   IntegerPrefMember prompt_for_download_android_;
   IntegerPrefMember prompt_for_download_later_;
 #endif
@@ -180,8 +180,8 @@
 
   std::unique_ptr<policy::URLBlocklist> auto_open_allowed_by_urls_;
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
   bool should_open_pdf_in_system_reader_;
 #endif
 
diff --git a/chrome/browser/download/download_prefs_unittest.cc b/chrome/browser/download/download_prefs_unittest.cc
index 780ca2d..f45ae7f 100644
--- a/chrome/browser/download/download_prefs_unittest.cc
+++ b/chrome/browser/download/download_prefs_unittest.cc
@@ -56,16 +56,16 @@
   content::BrowserTaskEnvironment task_environment_;
   base::HistogramTester histogram_tester;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(download::features::kDownloadLater);
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
   // Download prefs are registered when creating the profile.
   TestingProfile profile;
   DownloadPrefs prefs(&profile);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   // Download prompt prefs should be registered correctly.
   histogram_tester.ExpectBucketCount("MobileDownload.DownloadPromptStatus",
                                      DownloadPromptStatus::SHOW_INITIAL, 1);
@@ -81,7 +81,7 @@
           prefs::kDownloadLaterPromptStatus);
   EXPECT_EQ(download_later_prompt_status,
             static_cast<int>(DownloadLaterPromptStatus::kShowInitial));
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 }
 
 TEST(DownloadPrefsTest, NoAutoOpenByUserForDisallowedFileTypes) {
@@ -413,7 +413,7 @@
             download_prefs.GetDefaultDownloadDirectory());
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 void ExpectValidDownloadDir(Profile* profile,
                             DownloadPrefs* prefs,
                             base::FilePath path) {
@@ -543,9 +543,9 @@
     EXPECT_EQ(prefs2.DownloadPath(), default_dir2);
   }
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 TEST(DownloadPrefsTest, DownloadLaterPrefs) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(download::features::kDownloadLater);
@@ -597,6 +597,6 @@
   EXPECT_FALSE(prefs.PromptForDownload());
 }
 
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
 }  // namespace
diff --git a/chrome/browser/download/download_request_limiter_unittest.cc b/chrome/browser/download/download_request_limiter_unittest.cc
index 6a70d93..52b7fe0 100644
--- a/chrome/browser/download/download_request_limiter_unittest.cc
+++ b/chrome/browser/download/download_request_limiter_unittest.cc
@@ -32,7 +32,7 @@
 #include "third_party/blink/public/common/input/web_mouse_event.h"
 #include "third_party/blink/public/common/input/web_touch_event.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/flags/android/chrome_feature_list.h"
 #endif
 
diff --git a/chrome/browser/download/download_shelf_context_menu.cc b/chrome/browser/download/download_shelf_context_menu.cc
index 5b6d4720..cc967aa7 100644
--- a/chrome/browser/download/download_shelf_context_menu.cc
+++ b/chrome/browser/download/download_shelf_context_menu.cc
@@ -20,7 +20,7 @@
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/gfx/color_palette.h"
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
 #endif
 
@@ -171,11 +171,11 @@
             download_commands_->CanOpenPdfInSystemViewer();
         if (can_open_pdf_in_system_viewer) {
           id = IDS_DOWNLOAD_MENU_PLATFORM_OPEN_ALWAYS;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
           if (IsAdobeReaderDefaultPDFViewer())
             id = IDS_DOWNLOAD_MENU_ALWAYS_OPEN_PDF_IN_READER;
-#endif  // defined(_OS_WIN)
-                break;
+#endif  // BUILDFLAG(IS_WIN)
+          break;
         }
       }
       id = IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE;
@@ -337,7 +337,7 @@
 
   interrupted_download_menu_model_->AddItem(
       DownloadCommands::RESUME, GetLabelForCommandId(DownloadCommands::RESUME));
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // The Help Center article is currently Windows specific.
   // TODO(asanka): Enable this for other platforms when the article is expanded
   // for other platforms.
diff --git a/chrome/browser/download/download_stats.cc b/chrome/browser/download/download_stats.cc
index d14c5de1..1931196a 100644
--- a/chrome/browser/download/download_stats.cc
+++ b/chrome/browser/download/download_stats.cc
@@ -7,6 +7,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
 #include "base/notreached.h"
+#include "build/build_config.h"
 #include "components/profile_metrics/browser_profile_type.h"
 #include "components/safe_browsing/content/browser/download/download_stats.h"
 
@@ -87,7 +88,7 @@
       profile_metrics::GetBrowserProfileType(profile));
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 // Records whether the download dialog is shown to the user.
 void RecordDownloadPromptStatus(DownloadPromptStatus status) {
   base::UmaHistogramEnumeration("MobileDownload.DownloadPromptStatus", status,
@@ -99,13 +100,13 @@
                                 status);
 }
 
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 void RecordDownloadNotificationSuppressed() {
   base::UmaHistogramBoolean("Download.Notification.Suppressed", true);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 DownloadShelfContextMenuAction DownloadCommandToShelfAction(
     DownloadCommands::Command download_command,
diff --git a/chrome/browser/download/download_stats.h b/chrome/browser/download/download_stats.h
index bfa1d594f..f82b1e63 100644
--- a/chrome/browser/download/download_stats.h
+++ b/chrome/browser/download/download_stats.h
@@ -170,18 +170,18 @@
 
 void RecordDownloadStartPerProfileType(Profile* profile);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 // Records whether the download dialog is shown to the user.
 void RecordDownloadPromptStatus(DownloadPromptStatus status);
 
 // Records whether the download later dialog is shown to the user.
 void RecordDownloadLaterPromptStatus(DownloadLaterPromptStatus status);
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 // Records that a notification for a download was suppressed.
 void RecordDownloadNotificationSuppressed();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 enum class DownloadShelfContextMenuAction {
   // Drop down button for download shelf context menu is visible
diff --git a/chrome/browser/download/download_stats_unittest.cc b/chrome/browser/download/download_stats_unittest.cc
index 80276bb..f49ed7d 100644
--- a/chrome/browser/download/download_stats_unittest.cc
+++ b/chrome/browser/download/download_stats_unittest.cc
@@ -13,7 +13,7 @@
 
 constexpr char kDownloadCancelReasonHistogram[] = "Download.CancelReason";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 constexpr char kDownloadPromptStatusHistogram[] =
     "MobileDownload.DownloadPromptStatus";
 
@@ -42,7 +42,7 @@
   histogram_tester.ExpectTotalCount(kDownloadLaterPromptStatusHistogram, 1);
 }
 
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
 TEST(DownloadStatsTest, RecordDownloadCancelReason) {
   base::HistogramTester histogram_tester;
diff --git a/chrome/browser/download/download_status_updater.cc b/chrome/browser/download/download_status_updater.cc
index 2b26b635..1ea75052 100644
--- a/chrome/browser/download/download_status_updater.cc
+++ b/chrome/browser/download/download_status_updater.cc
@@ -177,7 +177,7 @@
   }
 }
 
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
 void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
     download::DownloadItem* download) {
   // TODO(avi): Implement for Android?
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc
index 5c63f94..2086f64f 100644
--- a/chrome/browser/download/download_target_determiner.cc
+++ b/chrome/browser/download/download_target_determiner.cc
@@ -17,6 +17,7 @@
 #include "base/task/thread_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/download/download_prefs.h"
@@ -58,7 +59,7 @@
 #include "content/public/common/webplugininfo.h"
 #endif
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
 #endif
 
@@ -83,7 +84,7 @@
       (result.first_visit.LocalMidnight() < base::Time::Now().LocalMidnight()));
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 // Keeps track of whether Adobe Reader is up to date.
 bool g_is_adobe_reader_up_to_date_ = false;
 #endif
@@ -109,7 +110,7 @@
       danger_level_(DownloadFileType::NOT_DANGEROUS),
       virtual_path_(initial_virtual_path),
       is_filetype_handled_safely_(false),
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
       is_checking_dialog_confirmed_path_(false),
 #endif
       download_(download),
@@ -226,7 +227,7 @@
   }
 
   bool no_prompt_needed = HasPromptedForPath();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   // If |virtual_path_| is content URI, there is no need to prompt the user.
   no_prompt_needed |= virtual_path_.IsContentUri();
 #endif
@@ -520,7 +521,7 @@
   // Avoid prompting for a download if it isn't in-progress. The user will be
   // prompted once the download is resumed and headers are available.
   if (download_->GetState() == DownloadItem::IN_PROGRESS) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
     // If we were looping back to check the user-confirmed path from the
     // dialog, and there were no additional errors, continue.
     if (is_checking_dialog_confirmed_path_ &&
@@ -552,7 +553,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!download_->IsTransient());
   DVLOG(20) << "User selected path:" << virtual_path.AsUTF8Unsafe();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   is_checking_dialog_confirmed_path_ = false;
   download_schedule_ = std::move(download_schedule);
 #endif
@@ -573,7 +574,7 @@
 
   virtual_path_ = virtual_path;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   if (result == DownloadConfirmationResult::CONFIRMED_WITH_DIALOG) {
     // Double check the user-selected path is valid by looping back.
     is_checking_dialog_confirmed_path_ = true;
@@ -764,7 +765,7 @@
 
   next_state_ = STATE_CHECK_DOWNLOAD_URL;
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   if (!local_path_.MatchesExtension(FILE_PATH_LITERAL(".pdf")))
     return CONTINUE;
   if (!IsAdobeReaderDefaultPDFViewer()) {
@@ -786,7 +787,7 @@
 #endif
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 void DownloadTargetDeterminer::DetermineIfAdobeReaderUpToDateDone(
     bool adobe_reader_up_to_date) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -903,7 +904,7 @@
 
   next_state_ = STATE_NONE;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   // If the local path is a content URI, the download should be from resumption
   // and we can just use the current path.
   if (local_path_.IsContentUri()) {
@@ -1179,7 +1180,7 @@
   return base::FilePath(suggested_path.value() + kCrdownloadSuffix);
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 // static
 bool DownloadTargetDeterminer::IsAdobeReaderUpToDate() {
   return g_is_adobe_reader_up_to_date_;
diff --git a/chrome/browser/download/download_target_determiner.h b/chrome/browser/download/download_target_determiner.h
index 3d19116..a983719 100644
--- a/chrome/browser/download/download_target_determiner.h
+++ b/chrome/browser/download/download_target_determiner.h
@@ -86,7 +86,7 @@
   // Returns a .crdownload intermediate path for the |suggested_path|.
   static base::FilePath GetCrDownloadPath(const base::FilePath& suggested_path);
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // Returns true if Adobe Reader is up to date. This information refreshed
   // only when Start() gets called for a PDF and Adobe Reader is the default
   // System PDF viewer.
@@ -257,7 +257,7 @@
   // - STATE_CHECK_DOWNLOAD_URL.
   Result DoDetermineIfAdobeReaderUpToDate();
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // Callback invoked when a decision is available about whether Adobe Reader
   // is up to date.
   void DetermineIfAdobeReaderUpToDateDone(bool adobe_reader_up_to_date);
@@ -355,7 +355,7 @@
   std::string mime_type_;
   bool is_filetype_handled_safely_;
   download::DownloadItem::MixedContentStatus mixed_content_status_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   bool is_checking_dialog_confirmed_path_;
 #endif
 
diff --git a/chrome/browser/download/download_target_determiner_unittest.cc b/chrome/browser/download/download_target_determiner_unittest.cc
index 2020807..0e9fe15 100644
--- a/chrome/browser/download/download_target_determiner_unittest.cc
+++ b/chrome/browser/download/download_target_determiner_unittest.cc
@@ -388,7 +388,7 @@
   test_virtual_dir_ = test_download_dir().Append(FILE_PATH_LITERAL("virtual"));
   delegate_.SetupDefaults();
   SetUpFileTypePolicies();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   profile()->GetTestingPrefService()->SetInteger(
       prefs::kPromptForDownloadAndroid,
       static_cast<int>(DownloadPromptStatus::DONT_SHOW));
@@ -474,7 +474,7 @@
 void DownloadTargetDeterminerTest::SetPromptForDownload(bool prompt) {
   profile()->GetTestingPrefService()->
       SetBoolean(prefs::kPromptForDownload, prompt);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   DownloadPromptStatus download_prompt_status =
       prompt ? DownloadPromptStatus::SHOW_PREFERENCE
              : DownloadPromptStatus::DONT_SHOW;
@@ -2442,7 +2442,7 @@
 }
 
 void ForceRefreshOfPlugins() {
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
   // Prevent creation of a utility process for loading plugins. Doing so breaks
   // unit_tests since /proc/self/exe can't be run as a utility process.
   content::RenderProcessHost::SetRunRendererInProcess(true);
@@ -2451,7 +2451,7 @@
   content::PluginService::GetInstance()->GetPlugins(
       base::BindOnce(&DummyGetPluginsCallback, run_loop.QuitClosure()));
   run_loop.Run();
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
   content::RenderProcessHost::SetRunRendererInProcess(false);
 #endif
 }
diff --git a/chrome/browser/download/download_ui_controller.cc b/chrome/browser/download/download_ui_controller.cc
index cebf264..371ef120 100644
--- a/chrome/browser/download/download_ui_controller.cc
+++ b/chrome/browser/download/download_ui_controller.cc
@@ -23,7 +23,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/download/android/download_controller.h"
 #include "chrome/browser/download/android/download_controller_base.h"
 #else
@@ -34,16 +34,16 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chrome/browser/download/notification/download_notification_manager.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 namespace {
 
 // DownloadShelfUIControllerDelegate{Android,} is used when a
 // DownloadUIController is
 // constructed without specifying an explicit Delegate.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 
 class AndroidUIControllerDelegate : public DownloadUIController::Delegate {
  public:
@@ -119,22 +119,22 @@
 DownloadUIController::DownloadUIController(content::DownloadManager* manager,
                                            std::unique_ptr<Delegate> delegate)
     : download_notifier_(manager, this), delegate_(std::move(delegate)) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   if (!delegate_)
     delegate_ = std::make_unique<AndroidUIControllerDelegate>();
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS)
   if (!delegate_) {
     // The Profile is guaranteed to be valid since DownloadUIController is owned
     // by DownloadService, which in turn is a profile keyed service.
     delegate_ = std::make_unique<DownloadNotificationManager>(
         Profile::FromBrowserContext(manager->GetBrowserContext()));
   }
-#else   // defined(OS_CHROMEOS)
+#else   // BUILDFLAG(IS_CHROMEOS)
   if (!delegate_) {
     delegate_ = std::make_unique<DownloadShelfUIControllerDelegate>(
         Profile::FromBrowserContext(manager->GetBrowserContext()));
   }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 }
 
 DownloadUIController::~DownloadUIController() {
@@ -201,7 +201,7 @@
   content::WebContents* web_contents =
       content::DownloadItemUtils::GetWebContents(item);
   if (web_contents) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
     DownloadController::CloseTabIfEmpty(web_contents, item);
 #else
     Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
@@ -217,7 +217,7 @@
         !item->IsSavePackageDownload()) {
       web_contents->Close();
     }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
   }
 
   if (item->GetState() == download::DownloadItem::CANCELLED)
diff --git a/chrome/browser/download/download_ui_model.cc b/chrome/browser/download/download_ui_model.cc
index 21dfd8e..5ab4497a 100644
--- a/chrome/browser/download/download_ui_model.cc
+++ b/chrome/browser/download/download_ui_model.cc
@@ -8,6 +8,7 @@
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/download/download_commands.h"
 #include "chrome/browser/download/offline_item_utils.h"
@@ -25,7 +26,7 @@
 #include "ui/base/l10n/time_format.h"
 #include "ui/base/text/bytes_formatting.h"
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/ui/browser.h"
 #endif
 
@@ -548,7 +549,7 @@
   return false;
 }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 bool DownloadUIModel::IsCommandEnabled(
     const DownloadCommands* download_commands,
     DownloadCommands::Command command) const {
diff --git a/chrome/browser/download/download_ui_model.h b/chrome/browser/download/download_ui_model.h
index b8ce5f8..40b37fbd 100644
--- a/chrome/browser/download/download_ui_model.h
+++ b/chrome/browser/download/download_ui_model.h
@@ -20,7 +20,7 @@
 #include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/content/common/proto/download_file_types.pb.h"
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/download/download_commands.h"
 #endif
 
@@ -315,7 +315,7 @@
   // security reasons.
   virtual bool ShouldPromoteOrigin() const;
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
   // Methods related to DownloadCommands.
   // Returns whether the given download command is enabled for this download.
   virtual bool IsCommandEnabled(const DownloadCommands* download_commands,
diff --git a/chrome/browser/download/mixed_content_download_blocking.cc b/chrome/browser/download/mixed_content_download_blocking.cc
index 958178d..2de44f87 100644
--- a/chrome/browser/download/mixed_content_download_blocking.cc
+++ b/chrome/browser/download/mixed_content_download_blocking.cc
@@ -196,7 +196,7 @@
     }
 
     // Extract extension.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
     extension_ = base::WideToUTF8(path.FinalExtension());
 #else
     extension_ = path.FinalExtension();
@@ -339,7 +339,7 @@
     const absl::optional<url::Origin>& initiator) {
   // TODO(crbug.com/1048957): Checking content settings crashes unit tests on
   // Android. It shouldn't.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
   ContentSettingsForOneType settings;
   HostContentSettingsMap* host_content_settings_map =
       HostContentSettingsMapFactory::GetForProfile(profile);
diff --git a/chrome/browser/download/offline_item_model.cc b/chrome/browser/download/offline_item_model.cc
index c8f45b28..5b4f9bb 100644
--- a/chrome/browser/download/offline_item_model.cc
+++ b/chrome/browser/download/offline_item_model.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "chrome/browser/download/offline_item_model_manager.h"
 #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -250,7 +251,7 @@
   return offline_item_ && offline_item_->promote_origin;
 }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
 bool OfflineItemModel::IsCommandEnabled(
     const DownloadCommands* download_commands,
     DownloadCommands::Command command) const {
diff --git a/chrome/browser/download/offline_item_model.h b/chrome/browser/download/offline_item_model.h
index 574f079..05cc032 100644
--- a/chrome/browser/download/offline_item_model.h
+++ b/chrome/browser/download/offline_item_model.h
@@ -67,7 +67,7 @@
   GURL GetOriginalURL() const override;
   bool ShouldPromoteOrigin() const override;
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
   bool IsCommandEnabled(const DownloadCommands* download_commands,
                         DownloadCommands::Command command) const override;
   bool IsCommandChecked(const DownloadCommands* download_commands,
diff --git a/chrome/browser/download/offline_item_utils.cc b/chrome/browser/download/offline_item_utils.cc
index 30a5867..b54c51f 100644
--- a/chrome/browser/download/offline_item_utils.cc
+++ b/chrome/browser/download/offline_item_utils.cc
@@ -15,7 +15,7 @@
 #include "third_party/blink/public/common/mime_util/mime_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/download/android/download_utils.h"
 #endif
 
@@ -78,7 +78,7 @@
 
 bool IsInterruptedDownloadAutoResumable(download::DownloadItem* item) {
   int auto_resumption_size_limit = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   auto_resumption_size_limit = DownloadUtils::GetAutoResumptionSizeLimit();
 #endif
 
@@ -112,7 +112,7 @@
   item.is_openable = download_item->CanOpenDownload();
   item.file_path = download_item->GetTargetFilePath();
   item.mime_type = download_item->GetMimeType();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   item.mime_type = DownloadUtils::RemapGenericMimeType(
       item.mime_type, download_item->GetOriginalUrl(),
       download_item->GetTargetFilePath().value());
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index 70a87f55..c6ef35b 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -438,7 +438,7 @@
   EXPECT_TRUE(base::PathExists(full_file_name));
   EXPECT_FALSE(base::PathExists(dir));
   EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name));
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // Local file URL will not be quarantined.
   EXPECT_FALSE(quarantine::IsFileQuarantined(full_file_name, GURL(), GURL()));
 #endif
@@ -467,7 +467,7 @@
 }
 
 // TODO(crbug.com/1271463): Flaky on mac arm64.
-#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
+#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
 #define MAYBE_SaveHTMLOnlyCancel DISABLED_SaveHTMLOnlyCancel
 #else
 #define MAYBE_SaveHTMLOnlyCancel SaveHTMLOnlyCancel
@@ -733,7 +733,7 @@
 // This tests that a webpage with the title "test.exe" is saved as
 // "test.exe.htm".
 // We probably don't care to handle this on Linux or Mac.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, CleanFilenameFromPageTitle) {
   base::FilePath download_dir =
       DownloadPrefs::FromDownloadManager(GetDownloadManager())->
@@ -774,7 +774,7 @@
 
 // Tests that a page can be saved as MHTML.
 // Flaky on Windows, crbug.com/1048100
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define MAYBE_SavePageAsMHTML DISABLED_SavePageAsMHTML
 #else
 #define MAYBE_SavePageAsMHTML SavePageAsMHTML
@@ -871,7 +871,7 @@
 }
 
 // Flaky on Windows: https://crbug.com/1247404.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define MAYBE_SavePageBrowserTest_NonMHTML DISABLED_SavePageBrowserTest_NonMHTML
 #else
 #define MAYBE_SavePageBrowserTest_NonMHTML SavePageBrowserTest_NonMHTML
@@ -987,7 +987,7 @@
   EXPECT_FALSE(base::PathExists(dir.AppendASCII("should-not-save.jpg")));
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 // Save a file and confirm that the file is correctly quarantined.
 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveURLQuarantine) {
   GURL url = embedded_test_server()->GetURL("/save_page/text.txt");
@@ -1097,7 +1097,7 @@
 
 // Test for crbug.com/538766.
 // Disabled on Mac due to excessive flakiness. https://crbug.com/1271741
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
 #define MAYBE_SaveAsMHTML DISABLED_SaveAsMHTML
 #else
 #define MAYBE_SaveAsMHTML SaveAsMHTML
@@ -1420,7 +1420,7 @@
 // Test compares original-vs-saved for a page with frames at about:blank uri.
 // This tests handling of iframe elements without src attribute (only with
 // srcdoc attribute) and how they get saved / cross-referenced.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
 // TODO(https://crbug.com/1262400): Fails on dcheck-enabled builds on 11.0.
 #define MAYBE_AboutBlank DISABLED_AboutBlank
 #else
@@ -1466,7 +1466,7 @@
 //   subframe1 and subframe2 - both have src=b.htm
 //   subframe3 and subframe4 - about:blank (no src, only srcdoc attribute).
 // ... but different content (generated by main frame's javascript).
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
 // TODO(https://crbug.com/1262400): Fails on dcheck-enabled builds on 11.0.
 #define MAYBE_RuntimeChanges DISABLED_RuntimeChanges
 #else
@@ -1527,7 +1527,7 @@
 }
 
 // Test for saving style element and attribute (see also crbug.com/568293).
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
 // TODO(https://crbug.com/1262400): Fails on dcheck-enabled builds on 11.0.
 #define MAYBE_Style DISABLED_Style
 #else
@@ -1566,7 +1566,7 @@
 
 // Test for saving a page with a cross-site <object> element.
 // Disabled on Windows due to flakiness. crbug.com/1070597.
-#if defined(OS_WIN) || defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 #define MAYBE_CrossSiteObject DISABLED_CrossSiteObject
 #else
 #define MAYBE_CrossSiteObject CrossSiteObject
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.cc
index 5630fe9a..aaddcdb 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_connector_service.cc
@@ -16,9 +16,8 @@
 
 namespace {
 
-const base::ListValue* GetPolicyUrlPatterns(PrefService* prefs) {
-  return &base::Value::AsListValue(
-      *prefs->GetList(kContextAwareAccessSignalsAllowlistPref));
+const base::Value* GetPolicyUrlPatterns(PrefService* prefs) {
+  return prefs->GetList(kContextAwareAccessSignalsAllowlistPref);
 }
 
 bool ConnectorPolicyHasValues(PrefService* profile_prefs) {
@@ -80,7 +79,7 @@
 void DeviceTrustConnectorService::OnPolicyUpdated() {
   DCHECK(IsDeviceTrustConnectorFeatureEnabled());
 
-  const base::ListValue* url_patterns = GetPolicyUrlPatterns(profile_prefs_);
+  const base::Value* url_patterns = GetPolicyUrlPatterns(profile_prefs_);
 
   if (!matcher_ || !matcher_->IsEmpty()) {
     // Reset the matcher.
@@ -89,7 +88,8 @@
 
   if (url_patterns && !url_patterns->GetList().empty()) {
     // Add the new endpoints to the conditions.
-    url_matcher::util::AddAllowFilters(matcher_.get(), url_patterns);
+    url_matcher::util::AddAllowFilters(
+        matcher_.get(), &base::Value::AsListValue(*url_patterns));
 
     // Call the hook which signals that the connector has been enabled.
     OnConnectorEnabled();
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 5501141..c104747e 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -18,7 +18,6 @@
 #include "base/containers/contains.h"
 #include "base/debug/alias.h"
 #include "base/debug/dump_without_crashing.h"
-#include "base/feature_list.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/metrics/histogram_functions.h"
@@ -97,11 +96,8 @@
 #include "extensions/browser/updater/extension_cache.h"
 #include "extensions/browser/updater/extension_downloader.h"
 #include "extensions/browser/updater/manifest_fetch_data.h"
-#include "extensions/common/extension_features.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/extension_urls.h"
-#include "extensions/common/feature_switch.h"
-#include "extensions/common/features/feature_channel.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handlers/incognito_info.h"
 #include "extensions/common/manifest_handlers/shared_module_info.h"
diff --git a/chrome/browser/feed/android/feed_process_scope_dependency_provider.cc b/chrome/browser/feed/android/feed_process_scope_dependency_provider.cc
index 916ce25..5ed05ba 100644
--- a/chrome/browser/feed/android/feed_process_scope_dependency_provider.cc
+++ b/chrome/browser/feed/android/feed_process_scope_dependency_provider.cc
@@ -5,8 +5,10 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
+#include "base/logging.h"
 #include "chrome/browser/feed/android/feed_service_factory.h"
 #include "chrome/browser/feed/android/jni_headers/FeedProcessScopeDependencyProvider_jni.h"
+#include "chrome/browser/feed/android/jni_translation.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/feed/core/proto/v2/ui.pb.h"
@@ -28,18 +30,6 @@
 
 static void JNI_FeedProcessScopeDependencyProvider_ProcessViewAction(
     JNIEnv* env,
-    const base::android::JavaParamRef<jbyteArray>& data) {
-  FeedApi* feed_stream_api = GetFeedApi();
-  if (!feed_stream_api)
-    return;
-  std::string data_string;
-  base::android::JavaByteArrayToString(env, data, &data_string);
-  feed_stream_api->ProcessViewAction(data_string);
-}
-
-static void
-JNI_FeedProcessScopeDependencyProvider_ProcessViewActionWithLoggingParameters(
-    JNIEnv* env,
     const base::android::JavaParamRef<jbyteArray>& action_data,
     const base::android::JavaParamRef<jbyteArray>& logging_parameters) {
   FeedApi* feed_stream_api = GetFeedApi();
@@ -47,16 +37,9 @@
     return;
   std::string action_data_string;
   base::android::JavaByteArrayToString(env, action_data, &action_data_string);
-  std::string logging_parameters_string;
-  base::android::JavaByteArrayToString(env, logging_parameters,
-                                       &logging_parameters_string);
-  feedui::LoggingParameters logging_parameters_value;
-  if (!logging_parameters_value.ParseFromString(logging_parameters_string)) {
-    DLOG(ERROR) << "Error parsing logging parameters";
-    return;
-  }
-  feed_stream_api->ProcessViewAction(action_data_string,
-                                     logging_parameters_value);
+
+  feed_stream_api->ProcessViewAction(
+      action_data_string, ToNativeLoggingParameters(env, logging_parameters));
 }
 
 static base::android::ScopedJavaLocalRef<jstring>
diff --git a/chrome/browser/feed/android/feed_service_bridge.cc b/chrome/browser/feed/android/feed_service_bridge.cc
index 4373d73..22161c90 100644
--- a/chrome/browser/feed/android/feed_service_bridge.cc
+++ b/chrome/browser/feed/android/feed_service_bridge.cc
@@ -73,16 +73,6 @@
   api->ReportOpenVisitComplete(base::Milliseconds(visitTimeMs));
 }
 
-static base::android::ScopedJavaLocalRef<jstring>
-JNI_FeedServiceBridge_GetClientInstanceId(JNIEnv* env) {
-  std::string instance_id;
-  FeedApi* api = GetFeedApi();
-  if (api) {
-    instance_id = api->GetClientInstanceId();
-  }
-  return base::android::ConvertUTF8ToJavaString(env, instance_id);
-}
-
 static int JNI_FeedServiceBridge_GetVideoPreviewsTypePreference(JNIEnv* env) {
   PrefService* pref_service = ProfileManager::GetLastUsedProfile()->GetPrefs();
   return pref_service->GetInteger(feed::prefs::kVideoPreviewsType);
diff --git a/chrome/browser/feed/android/feed_stream.cc b/chrome/browser/feed/android/feed_stream.cc
index 2003556..fa8d0d4b 100644
--- a/chrome/browser/feed/android/feed_stream.cc
+++ b/chrome/browser/feed/android/feed_stream.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/feed/android/feed_reliability_logging_bridge.h"
 #include "chrome/browser/feed/android/feed_service_factory.h"
 #include "chrome/browser/feed/android/jni_headers/FeedStream_jni.h"
+#include "chrome/browser/feed/android/jni_translation.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/feed/core/proto/v2/ui.pb.h"
@@ -119,12 +120,14 @@
 void FeedStream::ProcessThereAndBackAgain(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jbyteArray>& data) {
+    const JavaParamRef<jbyteArray>& data,
+    const JavaParamRef<jbyteArray>& logging_parameters) {
   if (!feed_stream_api_)
     return;
   std::string data_string;
   base::android::JavaByteArrayToString(env, data, &data_string);
-  feed_stream_api_->ProcessThereAndBackAgain(data_string);
+  feed_stream_api_->ProcessThereAndBackAgain(
+      data_string, ToNativeLoggingParameters(env, logging_parameters));
 }
 
 int FeedStream::ExecuteEphemeralChange(JNIEnv* env,
@@ -171,22 +174,6 @@
   }
 }
 
-bool FeedStream::IsActivityLoggingEnabled(JNIEnv* env,
-                                          const JavaParamRef<jobject>& obj) {
-  // Currently, the UI side isn't able to query streams independently for their
-  // logging activity state, and they will always ask for kForYouStream.
-  //
-  // We expect logging state to be in the same state for both streams, but we
-  // won't have this information if the stream isn't yet loaded.
-  // For this reason, we consider logging enabled as 'true' if it's enabled for
-  // either stream type.
-  // TODO(crbug.com/1268575): Remove IsActivityLoggingEnabled.
-
-  return feed_stream_api_ &&
-         (feed_stream_api_->IsActivityLoggingEnabled(kForYouStream) ||
-          feed_stream_api_->IsActivityLoggingEnabled(kWebFeedStream));
-}
-
 void FeedStream::ReportOpenAction(JNIEnv* env,
                                   const JavaParamRef<jobject>& obj,
                                   const JavaParamRef<jobject>& j_url,
diff --git a/chrome/browser/feed/android/feed_stream.h b/chrome/browser/feed/android/feed_stream.h
index 4eea2a82..5f99916 100644
--- a/chrome/browser/feed/android/feed_stream.h
+++ b/chrome/browser/feed/android/feed_stream.h
@@ -52,7 +52,8 @@
   void ProcessThereAndBackAgain(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jbyteArray>& data);
+      const base::android::JavaParamRef<jbyteArray>& data,
+      const base::android::JavaParamRef<jbyteArray>& logging_parameters);
 
   int ExecuteEphemeralChange(
       JNIEnv* env,
@@ -73,11 +74,6 @@
   void SurfaceClosed(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& obj);
 
-  // Is activity logging enabled (ephemeral).
-  bool IsActivityLoggingEnabled(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-
   // Event reporting functions. See |FeedApi| for definitions.
   void ReportSliceViewed(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java
index d1ebe99..7d986b05 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeDependencyProvider.java
@@ -20,15 +20,11 @@
 import org.chromium.chrome.browser.base.SplitCompatUtils;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManager;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.xsurface.ImageFetchClient;
 import org.chromium.chrome.browser.xsurface.LoggingParameters;
 import org.chromium.chrome.browser.xsurface.PersistentKeyValueCache;
 import org.chromium.chrome.browser.xsurface.ProcessScopeDependencyProvider;
 import org.chromium.chrome.browser.xsurface.ProcessScopeDependencyProvider.VisibilityLogType;
-import org.chromium.components.signin.base.CoreAccountInfo;
-import org.chromium.components.signin.identitymanager.ConsentLevel;
 import org.chromium.components.version_info.VersionConstants;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 
@@ -154,30 +150,6 @@
     }
 
     @Override
-    public String getAccountName() {
-        // Don't return account name if there's a signed-out session ID.
-        if (!getSignedOutSessionId().isEmpty()) {
-            return "";
-        }
-        assert ThreadUtils.runningOnUiThread();
-        CoreAccountInfo primaryAccount =
-                IdentityServicesProvider.get()
-                        .getIdentityManager(Profile.getLastUsedRegularProfile())
-                        .getPrimaryAccountInfo(ConsentLevel.SIGNIN);
-        return (primaryAccount == null) ? "" : primaryAccount.getEmail();
-    }
-
-    @Override
-    public String getClientInstanceId() {
-        // Don't return client instance id if there's a signed-out session ID.
-        if (!getSignedOutSessionId().isEmpty()) {
-            return "";
-        }
-        assert ThreadUtils.runningOnUiThread();
-        return FeedServiceBridge.getClientInstanceId();
-    }
-
-    @Override
     public int[] getExperimentIds() {
         // TODO(iwells): figure out why this is being called from another thread right after FRE
         if (!ThreadUtils.runningOnUiThread()) {
@@ -186,23 +158,13 @@
         return FeedProcessScopeDependencyProviderJni.get().getExperimentIds();
     }
 
-    @Override
-    public String getSignedOutSessionId() {
-        assert ThreadUtils.runningOnUiThread();
-        return FeedProcessScopeDependencyProviderJni.get().getSessionId();
-    }
-
     /**
      * Stores a view FeedAction for eventual upload. 'data' is a serialized FeedAction protobuf
      * message.
      */
     @Override
-    public void processViewAction(byte[] data) {
-        FeedProcessScopeDependencyProviderJni.get().processViewAction(data);
-    }
-    @Override
     public void processViewAction(byte[] data, LoggingParameters loggingParameters) {
-        FeedProcessScopeDependencyProviderJni.get().processViewActionWithLoggingParameters(
+        FeedProcessScopeDependencyProviderJni.get().processViewAction(
                 data, FeedLoggingParameters.convertToProto(loggingParameters).toByteArray());
     }
 
@@ -237,7 +199,6 @@
     public interface Natives {
         int[] getExperimentIds();
         String getSessionId();
-        void processViewAction(byte[] data);
-        void processViewActionWithLoggingParameters(byte[] actionData, byte[] loggingParameters);
+        void processViewAction(byte[] actionData, byte[] loggingParameters);
     }
 }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java
index 18d0c21..ad2421d 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java
@@ -121,10 +121,6 @@
         FeedServiceBridgeJni.get().startup();
     }
 
-    public static String getClientInstanceId() {
-        return FeedServiceBridgeJni.get().getClientInstanceId();
-    }
-
     /** Retrieves the config value for load_more_trigger_lookahead. */
     public static int getLoadMoreTriggerLookahead() {
         return FeedServiceBridgeJni.get().getLoadMoreTriggerLookahead();
@@ -205,7 +201,6 @@
         void startup();
         int getLoadMoreTriggerLookahead();
         int getLoadMoreTriggerScrollDistanceDp();
-        String getClientInstanceId();
         void reportOpenVisitComplete(long visitTimeMs);
         int getVideoPreviewsTypePreference();
         void setVideoPreviewsTypePreference(int videoPreviewsType);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
index 4be81f7..13048836 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
@@ -195,17 +195,12 @@
         static final String XSURFACE_CARD_URL = "Card URL";
 
         @Override
-        public void processThereAndBackAgainData(byte[] data) {
-            assert ThreadUtils.runningOnUiThread();
-            FeedStreamJni.get().processThereAndBackAgain(mNativeFeedStream, FeedStream.this, data);
-        }
-
-        @Override
         public void processThereAndBackAgainData(byte[] data, LoggingParameters loggingParameters) {
             assert ThreadUtils.runningOnUiThread();
             // TODO(crbug.com/1268575): Forward loggingParameters to FeedApi, and check that they
             // match the current state.
-            FeedStreamJni.get().processThereAndBackAgain(mNativeFeedStream, FeedStream.this, data);
+            FeedStreamJni.get().processThereAndBackAgain(mNativeFeedStream, FeedStream.this, data,
+                    FeedLoggingParameters.convertToProto(loggingParameters).toByteArray());
         }
 
         @Override
@@ -685,11 +680,6 @@
     }
 
     @Override
-    public boolean isActivityLoggingEnabled() {
-        return FeedStreamJni.get().isActivityLoggingEnabled(mNativeFeedStream, this);
-    }
-
-    @Override
     public void triggerRefresh(Callback<Boolean> callback) {
         PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
             if (mRenderer != null) {
@@ -1133,7 +1123,6 @@
     @VisibleForTesting
     public interface Natives {
         long init(FeedStream caller, boolean isForYou, long nativeFeedReliabilityLoggingBridge);
-        boolean isActivityLoggingEnabled(long nativeFeedStream, FeedStream caller);
         void reportFeedViewed(long nativeFeedStream, FeedStream caller);
         void reportSliceViewed(long nativeFeedStream, FeedStream caller, String sliceId);
         void reportPageLoaded(long nativeFeedStream, FeedStream caller, boolean inNewTab);
@@ -1146,7 +1135,8 @@
         void reportStreamScrollStart(long nativeFeedStream, FeedStream caller);
         void loadMore(long nativeFeedStream, FeedStream caller, Callback<Boolean> callback);
         void manualRefresh(long nativeFeedStream, FeedStream caller, Callback<Boolean> callback);
-        void processThereAndBackAgain(long nativeFeedStream, FeedStream caller, byte[] data);
+        void processThereAndBackAgain(
+                long nativeFeedStream, FeedStream caller, byte[] data, byte[] loggingParameters);
         int executeEphemeralChange(long nativeFeedStream, FeedStream caller, byte[] data);
         void commitEphemeralChange(long nativeFeedStream, FeedStream caller, int changeId);
         void discardEphemeralChange(long nativeFeedStream, FeedStream caller, int changeId);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
index e50873e..c4eb02b 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
@@ -25,19 +25,13 @@
     private final Activity mActivity;
     private final Context mActivityContext;
     private final boolean mDarkMode;
-    private final LoggingEnabledDelegate mLoggingEnabledDelegate;
     private final ObserverList<SurfaceHeaderOffsetObserver> mObserverList = new ObserverList<>();
 
-    public interface LoggingEnabledDelegate {
-        boolean isLoggingEnabledForCurrentStream();
-    }
-
-    public FeedSurfaceScopeDependencyProvider(Activity activity, Context activityContext,
-            boolean darkMode, LoggingEnabledDelegate loggingEnabledDelegate) {
+    public FeedSurfaceScopeDependencyProvider(
+            Activity activity, Context activityContext, boolean darkMode) {
         mActivityContext = FeedProcessScopeDependencyProvider.createFeedContext(activityContext);
         mDarkMode = darkMode;
         mActivity = activity;
-        mLoggingEnabledDelegate = loggingEnabledDelegate;
     }
 
     @Override
@@ -72,12 +66,6 @@
     }
 
     @Override
-    public boolean isActivityLoggingEnabled() {
-        assert ThreadUtils.runningOnUiThread();
-        return mLoggingEnabledDelegate.isLoggingEnabledForCurrentStream();
-    }
-
-    @Override
     public void reportVideoPlayEvent(boolean isMutedAutoplay, @VideoPlayEvent int event) {
         Log.i(TAG, "Feed video event %d", event);
         RecordHistogram.recordEnumeratedHistogram(
diff --git a/chrome/browser/feed/android/jni_translation.cc b/chrome/browser/feed/android/jni_translation.cc
new file mode 100644
index 0000000..b9a1674
--- /dev/null
+++ b/chrome/browser/feed/android/jni_translation.cc
@@ -0,0 +1,30 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/feed/android/jni_translation.h"
+
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/logging.h"
+#include "components/feed/core/proto/v2/ui.pb.h"
+
+namespace feed {
+namespace android {
+
+LoggingParameters ToNativeLoggingParameters(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jbyteArray>& logging_parameters) {
+  std::string bytes;
+  base::android::JavaByteArrayToString(env, logging_parameters, &bytes);
+  feedui::LoggingParameters logging_parameters_value;
+  if (!logging_parameters_value.ParseFromString(bytes)) {
+    DLOG(ERROR) << "Error parsing logging parameters";
+    return {};
+  }
+
+  return FromProto(logging_parameters_value);
+}
+
+}  // namespace android
+}  // namespace feed
diff --git a/chrome/browser/feed/android/jni_translation.h b/chrome/browser/feed/android/jni_translation.h
new file mode 100644
index 0000000..743843fc
--- /dev/null
+++ b/chrome/browser/feed/android/jni_translation.h
@@ -0,0 +1,23 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_FEED_ANDROID_JNI_TRANSLATION_H_
+#define CHROME_BROWSER_FEED_ANDROID_JNI_TRANSLATION_H_
+
+#include <jni.h>
+#include "base/android/jni_android.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
+
+// JNI <-> C++ translation functions needed in multiple cc files.
+namespace feed {
+namespace android {
+
+LoggingParameters ToNativeLoggingParameters(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jbyteArray>& logging_parameters);
+}
+
+}  // namespace feed
+
+#endif  // CHROME_BROWSER_FEED_ANDROID_JNI_TRANSLATION_H_
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc
index aca2bdde..e245608 100644
--- a/chrome/browser/feedback/show_feedback_page.cc
+++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -115,9 +115,7 @@
   if (IsGoogleInternalAccount(profile)) {
     flow = feedback_private::FeedbackFlow::FEEDBACK_FLOW_GOOGLEINTERNAL;
     include_bluetooth_logs = IsFromUserInteraction(source);
-    show_questionnaire = base::FeatureList::IsEnabled(
-                             ash::features::kShowFeedbackReportQuestionnaire) &&
-                         IsFromUserInteraction(source);
+    show_questionnaire = IsFromUserInteraction(source);
   }
 #endif
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index fc339a55..37541bd 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -620,7 +620,7 @@
   {
     "name": "button-arc-network-diagnostics",
     "owners": [ "arc-core@google.com"],
-    "expiry_milestone": 98
+    "expiry_milestone": 100
   },
   {
     "name": "bypass-app-banner-engagement-checks",
@@ -1965,12 +1965,12 @@
   {
     "name": "enable-experimental-accessibility-language-detection",
     "owners": [ "chrishall", "//ui/accessibility/OWNERS" ],
-    "expiry_milestone": 98
+    "expiry_milestone": 106
   },
   {
     "name": "enable-experimental-accessibility-language-detection-dynamic",
     "owners": [ "chrishall", "//ui/accessibility/OWNERS" ],
-    "expiry_milestone": 98
+    "expiry_milestone": 106
   },
   {
     "name": "enable-experimental-accessibility-switch-access-multistep-automation",
@@ -2245,7 +2245,7 @@
   {
     "name": "enable-local-web-approvals",
     "owners": [ "agawronska@chromium.org", "courtneywong@chromium.org", "danan@chromium.org" ],
-    "expiry_milestone": 98
+    "expiry_milestone": 104
   },
   {
     "name": "enable-lock-screen-notification",
@@ -2879,7 +2879,7 @@
   {
     "name": "enable-web-filter-interstitial-refresh",
     "owners": [ "agawronska@chromium.org", "courtneywong@chromium.org", "danan@chromium.org" ],
-    "expiry_milestone": 98
+    "expiry_milestone": 104
   },
   {
     "name": "enable-web-payments-experimental-features",
@@ -4340,7 +4340,7 @@
   {
     "name": "omnibox-trending-zero-prefix-suggestions-on-ntp",
     "owners": [ "mahmadi", "ender", "chrome-omnibox-team@google.com" ],
-    "expiry_milestone": 97
+    "expiry_milestone": 104
   },
   {
     "name": "omnibox-trigger-for-prerender2",
@@ -5126,11 +5126,6 @@
     "expiry_milestone": -1
   },
   {
-    "name": "show-feedback-report-questionnaire",
-    "owners": ["sonnysasaka"],
-    "expiry_milestone": 98
-  },
-  {
     "name": "show-metered-toggle",
     "owners": [ "stevenjb" ],
     "expiry_milestone": 100
@@ -5188,6 +5183,11 @@
     "expiry_milestone" : 100
   },
   {
+    "name": "single-cell-content-suggestions",
+    "owners": [ "thegreenfrog@google.com", "sczs@google.com"],
+    "expiry_milestone": 106
+  },
+  {
     "name": "single-ntp",
     "owners": [ "thegreenfrog@google.com", "sczs@google.com"],
     "expiry_milestone": 106
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index db2b1856..cda3524 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1720,7 +1720,7 @@
 const char kOmniboxTrendingZeroPrefixSuggestionsOnNTPName[] =
     "Omnibox Trending Zero Prefix Suggestions";
 const char kOmniboxTrendingZeroPrefixSuggestionsOnNTPDescription[] =
-    "Enables trending zero prefix suggestions for signed-in users with no or "
+    "Enables trending zero prefix suggestions for users with no or "
     "insufficient search history.";
 
 const char kOmniboxZeroSuggestPrefetchingName[] =
@@ -2159,17 +2159,6 @@
     "secure payment confirmation in PaymentRequest API must use user verifying "
     "platform authenticators.";
 
-const char kSendTabToSelfWhenSignedInName[] = "Send-tab-to-self when signed in";
-const char kSendTabToSelfWhenSignedInDescription[] =
-    "Makes the tab sharing feature also available for users who have \"only\" "
-    "signed-in to their Google Account (as opposed to having enabled Sync).";
-
-const char kSendTabToSelfManageDevicesLinkName[] =
-    "Send-tab-to-self manage devices link";
-const char kSendTabToSelfManageDevicesLinkDescription[] =
-    "Shows a link to manage the user's devices below the device list when "
-    "sharing";
-
 const char kShoppingListName[] = "Shopping List";
 const char kShoppingListDescription[] = "Enable shopping list in bookmarks.";
 
@@ -5053,11 +5042,6 @@
     "Enables a toggle which can enable debug (i.e., verbose) logs for "
     "Bluetooth";
 
-const char kShowFeedbackReportQuestionnaireName[] =
-    "Show feedback report questionnaire";
-const char kShowFeedbackReportQuestionnaireDescription[] =
-    "Show domain-related questionnaire in feedback report UI";
-
 const char kBluetoothSessionizedMetricsName[] =
     "Enable Bluetooth sessionized metrics";
 const char kBluetoothSessionizedMetricsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 012deca..2c6fdfaf 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1230,12 +1230,6 @@
 extern const char kSecurePaymentConfirmationDebugName[];
 extern const char kSecurePaymentConfirmationDebugDescription[];
 
-extern const char kSendTabToSelfWhenSignedInName[];
-extern const char kSendTabToSelfWhenSignedInDescription[];
-
-extern const char kSendTabToSelfManageDevicesLinkName[];
-extern const char kSendTabToSelfManageDevicesLinkDescription[];
-
 extern const char kShoppingListName[];
 extern const char kShoppingListDescription[];
 
@@ -2903,9 +2897,6 @@
 extern const char kShowBluetoothDebugLogToggleName[];
 extern const char kShowBluetoothDebugLogToggleDescription[];
 
-extern const char kShowFeedbackReportQuestionnaireName[];
-extern const char kShowFeedbackReportQuestionnaireDescription[];
-
 extern const char kBluetoothSessionizedMetricsName[];
 extern const char kBluetoothSessionizedMetricsDescription[];
 
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 08839dff..6dca830 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -405,13 +405,7 @@
             "OfflinePagesDescriptivePendingStatus";
     public static final String OFFLINE_PAGES_LIVE_PAGE_SHARING = "OfflinePagesLivePageSharing";
     public static final String OFFLINE_PAGES_PREFETCHING = "OfflinePagesPrefetching";
-    public static final String OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT =
-            "OmniboxAdaptiveSuggestionsCount";
     public static final String OMNIBOX_ASSISTANT_VOICE_SEARCH = "OmniboxAssistantVoiceSearch";
-    public static final String OMNIBOX_ENABLE_CLIPBOARD_PROVIDER_IMAGE_SUGGESTIONS =
-            "OmniboxEnableClipboardProviderImageSuggestions";
-    public static final String OMNIBOX_MOST_VISITED_TILES = "OmniboxMostVisitedTiles";
-    public static final String OMNIBOX_SPARE_RENDERER = "OmniboxSpareRenderer";
     public static final String OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS =
             "OmniboxUpdatedConnectionSecurityIndicators";
     public static final String OPTIMIZATION_GUIDE_PUSH_NOTIFICATIONS =
diff --git a/chrome/browser/media/capture_access_handler_base.cc b/chrome/browser/media/capture_access_handler_base.cc
index a5bbaf1..0dbb6d54 100644
--- a/chrome/browser/media/capture_access_handler_base.cc
+++ b/chrome/browser/media/capture_access_handler_base.cc
@@ -89,12 +89,14 @@
     const content::MediaStreamRequest& request,
     content::MediaResponseCallback callback,
     std::u16string application_title,
-    bool should_display_notification)
+    bool should_display_notification,
+    bool is_allowlisted_extension)
     : picker(std::move(picker)),
       request(request),
       callback(std::move(callback)),
       application_title(std::move(application_title)),
-      should_display_notification(should_display_notification) {}
+      should_display_notification(should_display_notification),
+      is_allowlisted_extension(is_allowlisted_extension) {}
 
 CaptureAccessHandlerBase::PendingAccessRequest::~PendingAccessRequest() =
     default;
diff --git a/chrome/browser/media/capture_access_handler_base.h b/chrome/browser/media/capture_access_handler_base.h
index 48b4aef0..2300cce1 100644
--- a/chrome/browser/media/capture_access_handler_base.h
+++ b/chrome/browser/media/capture_access_handler_base.h
@@ -60,7 +60,8 @@
                          const content::MediaStreamRequest& request,
                          content::MediaResponseCallback callback,
                          std::u16string application_title,
-                         bool should_display_notification);
+                         bool should_display_notification,
+                         bool is_allowlisted_extension);
     PendingAccessRequest(const PendingAccessRequest& other) = delete;
     PendingAccessRequest& operator=(const PendingAccessRequest& other) = delete;
     ~PendingAccessRequest();
@@ -69,7 +70,8 @@
     content::MediaStreamRequest request;
     content::MediaResponseCallback callback;
     std::u16string application_title;
-    bool should_display_notification;
+    const bool should_display_notification;
+    const bool is_allowlisted_extension;
   };
 
   using RequestsQueue =
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
index 1dc6294..d95ec5c 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/check.h"
 #include "base/command_line.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_number_conversions.h"
@@ -227,49 +228,42 @@
 
 void DesktopCaptureAccessHandler::ProcessScreenCaptureAccessRequest(
     content::WebContents* web_contents,
-    const content::MediaStreamRequest& request,
-    content::MediaResponseCallback callback,
-    const extensions::Extension* extension) {
-  DCHECK_EQ(request.video_type,
+    const std::u16string& application_title,
+    std::unique_ptr<PendingAccessRequest> pending_request) {
+  DCHECK_EQ(pending_request->request.video_type,
             blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE);
 
-  UpdateExtensionTrusted(request,
-                         IsExtensionAllowedForScreenCapture(extension));
-
-  const bool is_allowlisted_extension =
-      IsExtensionAllowedForScreenCapture(extension);
+  UpdateExtensionTrusted(pending_request->request,
+                         pending_request->is_allowlisted_extension);
 
   const bool screen_capture_enabled =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableUserMediaScreenCapturing) ||
-      is_allowlisted_extension || IsBuiltInFeedbackUI(request.security_origin);
+      pending_request->is_allowlisted_extension ||
+      IsBuiltInFeedbackUI(pending_request->request.security_origin);
 
   const bool origin_is_secure =
-      network::IsUrlPotentiallyTrustworthy(request.security_origin) ||
+      network::IsUrlPotentiallyTrustworthy(
+          pending_request->request.security_origin) ||
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kAllowHttpScreenCapture);
 
   if (!screen_capture_enabled || !origin_is_secure) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::INVALID_STATE, nullptr);
-    return;
-  }
-
-  if (!IsRequestApproved(web_contents, request, extension,
-                         is_allowlisted_extension)) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, nullptr);
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+             /*ui=*/nullptr);
     return;
   }
 
   if (!content::WebContents::FromRenderFrameHost(
-          content::RenderFrameHost::FromID(request.render_process_id,
-                                           request.render_frame_id))) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::INVALID_STATE, nullptr);
+          content::RenderFrameHost::FromID(
+              pending_request->request.render_process_id,
+              pending_request->request.render_frame_id))) {
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+             /*ui=*/nullptr);
     return;
   }
 
@@ -282,9 +276,10 @@
               : ash::Shell::Get()->GetPrimaryRootWindow());
   if (policy::DlpContentManagerAsh::Get()->IsScreenCaptureRestricted(
           screen_id)) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, nullptr);
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+             /*ui=*/nullptr);
     return;
   }
 #else   // BUILDFLAG(IS_CHROMEOS_ASH)
@@ -293,28 +288,11 @@
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
   const bool capture_audio =
-      (request.audio_type ==
-           blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE &&
-       kIsLoopbackAudioSupported);
-
-  // Determine if the extension is required to display a notification.
-  const bool display_notification =
-      display_notification_ && ShouldDisplayNotification(extension) &&
-      !HasNotificationExemption(request.security_origin);
-
-  const std::u16string application_title =
-      GetApplicationTitle(web_contents, extension);
-
-  blink::MediaStreamDevices devices;
-  std::unique_ptr<content::MediaStreamUI> ui;
-  ui = GetDevicesForDesktopCapture(request, web_contents, screen_id,
-                                   capture_audio, request.disable_local_echo,
-                                   display_notification, application_title,
-                                   &devices);
-  DCHECK(!devices.empty());
-
-  std::move(callback).Run(devices, blink::mojom::MediaStreamRequestResult::OK,
-                          std::move(ui));
+      pending_request->request.audio_type ==
+          blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE &&
+      kIsLoopbackAudioSupported;
+  AcceptRequest(web_contents, std::move(pending_request), screen_id,
+                capture_audio);
 }
 
 bool DesktopCaptureAccessHandler::SupportsStreamType(
@@ -340,11 +318,23 @@
     const extensions::Extension* extension) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
+  const bool is_allowlisted_extension =
+      IsExtensionAllowedForScreenCapture(extension);
+  const bool should_display_notification =
+      display_notification_ && ShouldDisplayNotification(extension) &&
+      !HasNotificationExemption(request.security_origin);
+  std::unique_ptr<PendingAccessRequest> pending_request =
+      std::make_unique<PendingAccessRequest>(
+          /*picker=*/nullptr, request, std::move(callback),
+          GetApplicationTitle(web_contents, extension),
+          should_display_notification, is_allowlisted_extension);
+
   if (request.video_type !=
       blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::INVALID_STATE, nullptr);
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+             /*ui=*/nullptr);
     return;
   }
 
@@ -353,15 +343,15 @@
                                              web_contents);
 
   if (allowed_capture_level == AllowedScreenCaptureLevel::kDisallowed) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, nullptr);
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+             /*ui=*/nullptr);
     return;
   }
 
   if (request.request_type == blink::MEDIA_DEVICE_UPDATE) {
-    ProcessChangeSourceRequest(web_contents, request, std::move(callback),
-                               extension);
+    ProcessChangeSourceRequest(web_contents, std::move(pending_request));
     return;
   }
 
@@ -369,66 +359,93 @@
   // (i.e. chooseDesktopMedia() API wasn't used to generate device id).
   if (request.requested_video_device_id.empty()) {
     if (allowed_capture_level < AllowedScreenCaptureLevel::kDesktop) {
-      std::move(callback).Run(
-          blink::MediaStreamDevices(),
-          blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, nullptr);
+      std::move(pending_request->callback)
+          .Run(blink::MediaStreamDevices(),
+               blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+               /*ui=*/nullptr);
       return;
     }
 #if defined(OS_MAC)
     if (system_media_permissions::CheckSystemScreenCapturePermission() !=
         system_media_permissions::SystemPermission::kAllowed) {
-      std::move(callback).Run(
-          blink::MediaStreamDevices(),
-          blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
-          nullptr);
+      std::move(pending_request->callback)
+          .Run(blink::MediaStreamDevices(),
+               blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
+               /*ui=*/nullptr);
       return;
     }
 #endif
-    ProcessScreenCaptureAccessRequest(web_contents, request,
-                                      std::move(callback), extension);
+    if (!IsRequestApproved(web_contents, request, extension,
+                           is_allowlisted_extension)) {
+      std::move(pending_request->callback)
+          .Run(blink::MediaStreamDevices(),
+               blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+               /*ui=*/nullptr);
+      return;
+    }
+
+    ProcessScreenCaptureAccessRequest(
+        web_contents, GetApplicationTitle(web_contents, extension),
+        std::move(pending_request));
     return;
   }
 
   // Resolve DesktopMediaID for the specified device id.
-  content::DesktopMediaID media_id =
-      content::DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId(
-          request.requested_video_device_id, request.render_process_id,
-          request.render_frame_id, url::Origin::Create(request.security_origin),
-          nullptr, content::kRegistryStreamTypeDesktop);
+  content::DesktopMediaID media_id;
+  // TODO(http://crbug.com/304341): Replace "main RenderFrame" IDs with the
+  // request's actual RenderFrame IDs once the desktop capture extension API
+  // implementation is fixed.
+  content::WebContents* const web_contents_for_stream =
+      content::WebContents::FromRenderFrameHost(
+          content::RenderFrameHost::FromID(request.render_process_id,
+                                           request.render_frame_id));
+  content::RenderFrameHost* const main_frame =
+      web_contents_for_stream ? web_contents_for_stream->GetMainFrame()
+                              : nullptr;
+  if (main_frame) {
+    media_id =
+        content::DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId(
+            request.requested_video_device_id,
+            main_frame->GetProcess()->GetID(), main_frame->GetRoutingID(),
+            url::Origin::Create(request.security_origin),
+            /*extension_name=*/nullptr, content::kRegistryStreamTypeDesktop);
+  }
 
   // Received invalid device id.
   if (media_id.type == content::DesktopMediaID::TYPE_NONE) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::INVALID_STATE, nullptr);
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+             /*ui=*/nullptr);
     return;
   }
 
   if (!IsMediaTypeAllowed(allowed_capture_level, media_id.type)) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, nullptr);
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+             /*ui=*/nullptr);
     return;
   }
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  {
-    if (policy::DlpContentManagerAsh::Get()->IsScreenCaptureRestricted(
-            media_id)) {
-      std::move(callback).Run(
-          blink::MediaStreamDevices(),
-          blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, nullptr);
-      return;
-    }
+  if (policy::DlpContentManagerAsh::Get()->IsScreenCaptureRestricted(
+          media_id)) {
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+             /*ui=*/nullptr);
+    return;
   }
 #endif
 #if defined(OS_MAC)
   if (media_id.type != content::DesktopMediaID::TYPE_WEB_CONTENTS &&
       system_media_permissions::CheckSystemScreenCapturePermission() !=
           system_media_permissions::SystemPermission::kAllowed) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
-        nullptr);
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
+             /*ui=*/nullptr);
     return;
   }
 #endif
@@ -438,42 +455,32 @@
           content::RenderFrameHost::FromID(
               media_id.web_contents_id.render_process_id,
               media_id.web_contents_id.main_render_frame_id))) {
-    std::move(callback).Run(
-        blink::MediaStreamDevices(),
-        blink::mojom::MediaStreamRequestResult::TAB_CAPTURE_FAILURE, nullptr);
+    std::move(pending_request->callback)
+        .Run(blink::MediaStreamDevices(),
+             blink::mojom::MediaStreamRequestResult::TAB_CAPTURE_FAILURE,
+             /*ui=*/nullptr);
     return;
   }
 
-  blink::MediaStreamDevices devices;
-  std::unique_ptr<content::MediaStreamUI> ui;
-  ui = GetDevicesForDesktopCapture(
-      request, web_contents, media_id, ShouldCaptureAudio(media_id, request),
-      request.disable_local_echo,
-      (display_notification_ && ShouldDisplayNotification(extension)),
-      GetApplicationTitle(web_contents, extension), &devices);
-  UpdateExtensionTrusted(request,
-                         IsExtensionAllowedForScreenCapture(extension));
-  std::move(callback).Run(devices, blink::mojom::MediaStreamRequestResult::OK,
-                          std::move(ui));
+  AcceptRequest(web_contents, std::move(pending_request), media_id,
+                ShouldCaptureAudio(media_id, request));
 }
 
 void DesktopCaptureAccessHandler::ProcessChangeSourceRequest(
     content::WebContents* web_contents,
-    const content::MediaStreamRequest& request,
-    content::MediaResponseCallback callback,
-    const extensions::Extension* extension) {
+    std::unique_ptr<PendingAccessRequest> pending_request) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK_EQ(request.video_type,
+  DCHECK_EQ(pending_request->request.video_type,
             blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE);
 
-  std::unique_ptr<DesktopMediaPicker> picker;
-
-  if (request.requested_video_device_id.empty()) {
-    picker = picker_factory_->CreatePicker(&request);
-    if (!picker) {
-      std::move(callback).Run(
-          blink::MediaStreamDevices(),
-          blink::mojom::MediaStreamRequestResult::INVALID_STATE, nullptr);
+  if (pending_request->request.requested_video_device_id.empty()) {
+    pending_request->picker =
+        picker_factory_->CreatePicker(&pending_request->request);
+    if (!pending_request->picker) {
+      std::move(pending_request->callback)
+          .Run(blink::MediaStreamDevices(),
+               blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+               /*ui=*/nullptr);
       return;
     }
   }
@@ -482,10 +489,7 @@
   web_contents_collection_.StartObserving(web_contents);
 
   RequestsQueue& queue = pending_requests_[web_contents];
-  queue.push_back(std::make_unique<PendingAccessRequest>(
-      std::move(picker), request, std::move(callback),
-      GetApplicationTitle(web_contents, extension),
-      display_notification_ && ShouldDisplayNotification(extension)));
+  queue.push_back(std::move(pending_request));
   // If this is the only request then pop picker UI.
   if (queue.size() == 1)
     ProcessQueuedAccessRequest(queue, web_contents);
@@ -534,7 +538,8 @@
           content::DesktopMediaID::kNullId, web_contents_id);
       media_id.audio_share = pending_request.request.audio_type !=
                              blink::mojom::MediaStreamType::NO_SERVICE;
-      OnPickerDialogResults(web_contents, media_id);
+      OnPickerDialogResults(web_contents, pending_request.application_title,
+                            media_id);
       return;
     }
   }
@@ -550,9 +555,9 @@
       {DesktopMediaList::Type::kWebContents}, web_contents,
       std::move(includable_web_contents_filter));
 
-  DesktopMediaPicker::DoneCallback done_callback =
-      base::BindOnce(&DesktopCaptureAccessHandler::OnPickerDialogResults,
-                     base::Unretained(this), web_contents);
+  DesktopMediaPicker::DoneCallback done_callback = base::BindOnce(
+      &DesktopCaptureAccessHandler::OnPickerDialogResults,
+      base::Unretained(this), web_contents, pending_request.application_title);
   DesktopMediaPicker::Params picker_params;
   picker_params.web_contents = web_contents;
   gfx::NativeWindow parent_window = web_contents->GetTopLevelNativeWindow();
@@ -574,6 +579,7 @@
 
 void DesktopCaptureAccessHandler::OnPickerDialogResults(
     content::WebContents* web_contents,
+    const std::u16string& application_title,
     content::DesktopMediaID media_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(web_contents);
@@ -588,45 +594,32 @@
     return;
   }
 
-  PendingAccessRequest& pending_request = *queue.front();
+  std::unique_ptr<PendingAccessRequest> pending_request =
+      std::move(queue.front());
+  queue.pop_front();
 
   if (media_id.is_null()) {
-    std::move(pending_request.callback)
+    std::move(pending_request->callback)
         .Run(blink::MediaStreamDevices(),
              blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
-             nullptr);
-
-    queue.pop_front();
-    if (!queue.empty())
-      ProcessQueuedAccessRequest(queue, web_contents);
-    return;
-  }
-
+             /*ui=*/nullptr);
+  } else {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (policy::DlpContentManagerAsh::Get()->IsScreenCaptureRestricted(
-          media_id)) {
-    std::move(pending_request.callback)
-        .Run(blink::MediaStreamDevices(),
-             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
-             nullptr);
-
-    queue.pop_front();
-    if (!queue.empty())
-      ProcessQueuedAccessRequest(queue, web_contents);
-    return;
-  }
+    if (policy::DlpContentManagerAsh::Get()->IsScreenCaptureRestricted(
+            media_id)) {
+      std::move(pending_request->callback)
+          .Run(blink::MediaStreamDevices(),
+               blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+               /*ui=*/nullptr);
+    } else {
+      AcceptRequest(web_contents, std::move(pending_request), media_id,
+                    media_id.audio_share);
+    }
+#else
+    AcceptRequest(web_contents, std::move(pending_request), media_id,
+                  media_id.audio_share);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
-  blink::MediaStreamDevices devices;
-  std::unique_ptr<content::MediaStreamUI> ui = GetDevicesForDesktopCapture(
-      pending_request.request, web_contents, media_id, media_id.audio_share,
-      pending_request.request.disable_local_echo,
-      pending_request.should_display_notification,
-      pending_request.application_title, &devices);
-  std::move(pending_request.callback)
-      .Run(devices, blink::mojom::MediaStreamRequestResult::OK, std::move(ui));
-
-  queue.pop_front();
+  }
   if (!queue.empty())
     ProcessQueuedAccessRequest(queue, web_contents);
 }
@@ -655,3 +648,26 @@
     }
   }
 }
+
+void DesktopCaptureAccessHandler::AcceptRequest(
+    content::WebContents* web_contents,
+    std::unique_ptr<PendingAccessRequest> pending_request,
+    const content::DesktopMediaID& media_id,
+    bool capture_audio) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(web_contents);
+
+  blink::MediaStreamDevices devices;
+  std::unique_ptr<content::MediaStreamUI> ui = GetDevicesForDesktopCapture(
+      pending_request->request, web_contents, media_id, capture_audio,
+      pending_request->request.disable_local_echo,
+      pending_request->should_display_notification,
+      pending_request->application_title, &devices);
+  DCHECK(!devices.empty());
+
+  UpdateExtensionTrusted(pending_request->request,
+                         pending_request->is_allowlisted_extension);
+
+  std::move(pending_request->callback)
+      .Run(devices, blink::mojom::MediaStreamRequestResult::OK, std::move(ui));
+}
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler.h b/chrome/browser/media/webrtc/desktop_capture_access_handler.h
index 0ccc2915..6b78947 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler.h
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler.h
@@ -7,6 +7,7 @@
 
 #include <list>
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "base/containers/flat_map.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/media/webrtc/desktop_media_picker_factory.h"
 #include "chrome/browser/tab_contents/web_contents_collection.h"
 #include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/media_stream_request.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 namespace aura {
@@ -29,6 +31,10 @@
 class Extension;
 }
 
+namespace contents {
+class WebContents;
+}
+
 // MediaAccessHandler for DesktopCapture API requests that originate from
 // getUserMedia() calls. Note that getDisplayMedia() calls are handled in
 // DisplayMediaAccessHandler.
@@ -69,27 +75,32 @@
 
   void ProcessScreenCaptureAccessRequest(
       content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      content::MediaResponseCallback callback,
-      const extensions::Extension* extension);
+      const std::u16string& application_title,
+      std::unique_ptr<PendingAccessRequest> pending_request);
 
   // WebContentsCollection::Observer:
   void WebContentsDestroyed(content::WebContents* web_contents) override;
 
   // Methods for handling source change request, e.g. bringing up the picker to
   // select a new source within the current desktop sharing session.
-  void ProcessChangeSourceRequest(content::WebContents* web_contents,
-                                  const content::MediaStreamRequest& request,
-                                  content::MediaResponseCallback callback,
-                                  const extensions::Extension* extension);
+  void ProcessChangeSourceRequest(
+      content::WebContents* web_contents,
+      std::unique_ptr<PendingAccessRequest> pending_request);
   void ProcessQueuedAccessRequest(const RequestsQueue& queue,
                                   content::WebContents* web_contents);
   void OnPickerDialogResults(content::WebContents* web_contents,
+                             const std::u16string& application_title,
                              content::DesktopMediaID source);
   void DeletePendingAccessRequest(int render_process_id,
                                   int render_frame_id,
                                   int page_request_id);
 
+  // Helper method to finalize processing an approved request.
+  void AcceptRequest(content::WebContents* web_contents,
+                     std::unique_ptr<PendingAccessRequest> pending_request,
+                     const content::DesktopMediaID& media_id,
+                     bool capture_audio);
+
   std::unique_ptr<DesktopMediaPickerFactory> picker_factory_;
   bool display_notification_;
   RequestsQueues pending_requests_;
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.cc b/chrome/browser/media/webrtc/display_media_access_handler.cc
index 0423c6b..fb8c88f 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/display_media_access_handler.cc
@@ -202,7 +202,8 @@
 
   queue.push_back(std::make_unique<PendingAccessRequest>(
       std::move(picker), request, std::move(callback),
-      GetApplicationTitle(web_contents), display_notification_));
+      GetApplicationTitle(web_contents), display_notification_,
+      /*is_allowlisted_extension=*/false));
   // If this is the only request then pop picker UI.
   if (queue.size() == 1)
     ProcessQueuedAccessRequest(queue, web_contents);
@@ -220,7 +221,8 @@
   RequestsQueue& queue = pending_requests_[web_contents];
   queue.push_back(std::make_unique<PendingAccessRequest>(
       /*picker=*/nullptr, request, std::move(callback),
-      GetApplicationTitle(web_contents), display_notification_));
+      GetApplicationTitle(web_contents), display_notification_,
+      /*is_allowlisted_extension=*/false));
   // If this is the only request then pop it. Otherwise, there is already a task
   // scheduled to pop the next request.
   if (queue.size() == 1)
diff --git a/chrome/browser/media/webrtc/tab_capture_access_handler.cc b/chrome/browser/media/webrtc/tab_capture_access_handler.cc
index c5c667e..49a2cebd 100644
--- a/chrome/browser/media/webrtc/tab_capture_access_handler.cc
+++ b/chrome/browser/media/webrtc/tab_capture_access_handler.cc
@@ -191,13 +191,14 @@
     // destroyed when the browser process terminates.
     policy::DlpContentManagerAsh::Get()->CheckScreenShareRestriction(
         media_id, application_title,
-        base::BindOnce(&TabCaptureAccessHandler::OnDlpRestrictionChecked,
-                       base::Unretained(this), web_contents->GetWeakPtr(),
-                       std::make_unique<PendingAccessRequest>(
-                           /*picker=*/nullptr, request, std::move(callback),
-                           application_title,
-                           /*display_notification=*/false),
-                       is_allowlisted_extension, std::move(media_ui)));
+        base::BindOnce(
+            &TabCaptureAccessHandler::OnDlpRestrictionChecked,
+            base::Unretained(this), web_contents->GetWeakPtr(),
+            std::make_unique<PendingAccessRequest>(
+                /*picker=*/nullptr, request, std::move(callback),
+                application_title,
+                /*display_notification=*/false, is_allowlisted_extension),
+            std::move(media_ui)));
     return;
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
@@ -229,7 +230,6 @@
 void TabCaptureAccessHandler::OnDlpRestrictionChecked(
     base::WeakPtr<content::WebContents> web_contents,
     std::unique_ptr<PendingAccessRequest> pending_request,
-    bool is_allowlisted_extension,
     std::unique_ptr<MediaStreamUI> media_ui,
     bool is_dlp_allowed) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -241,7 +241,8 @@
   if (is_dlp_allowed) {
     AcceptRequest(web_contents.get(), pending_request->request,
                   std::move(pending_request->callback),
-                  is_allowlisted_extension, std::move(media_ui));
+                  pending_request->is_allowlisted_extension,
+                  std::move(media_ui));
   } else {
     std::move(pending_request->callback)
         .Run(blink::MediaStreamDevices(),
diff --git a/chrome/browser/media/webrtc/tab_capture_access_handler.h b/chrome/browser/media/webrtc/tab_capture_access_handler.h
index 1be7b5ce..1d2d527 100644
--- a/chrome/browser/media/webrtc/tab_capture_access_handler.h
+++ b/chrome/browser/media/webrtc/tab_capture_access_handler.h
@@ -48,7 +48,6 @@
   void OnDlpRestrictionChecked(
       base::WeakPtr<content::WebContents> web_contents,
       std::unique_ptr<PendingAccessRequest> pending_request,
-      bool is_allowlisted_extension,
       std::unique_ptr<MediaStreamUI> media_ui,
       bool is_dlp_allowed);
 
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
index a9bc66b..7ae0061 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
@@ -625,8 +625,10 @@
 #endif
 IN_PROC_BROWSER_TEST_F(ProcessMemoryMetricsEmitterTest,
                        MAYBE_HasZombieProfile) {
-  ASSERT_TRUE(
-      base::FeatureList::IsEnabled(features::kDestroyProfileOnBrowserClose));
+  // We observe Profile destruction in this test, so skip it for the handful of
+  // bots that don't destroy Profiles.
+  if (!base::FeatureList::IsEnabled(features::kDestroyProfileOnBrowserClose))
+    GTEST_SKIP();
 
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL url = embedded_test_server()->GetURL("foo.com", "/empty.html");
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.cc b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.cc
new file mode 100644
index 0000000..79ae5a8
--- /dev/null
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.cc
@@ -0,0 +1,13 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h"
+
+#include "chromeos/network/firewall_hole.h"
+
+NearbyConnectionsFirewallHole::NearbyConnectionsFirewallHole(
+    std::unique_ptr<chromeos::FirewallHole> firewall_hole)
+    : firewall_hole_(std::move(firewall_hole)) {}
+
+NearbyConnectionsFirewallHole::~NearbyConnectionsFirewallHole() = default;
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h
new file mode 100644
index 0000000..d93dce17
--- /dev/null
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h
@@ -0,0 +1,32 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NEARBY_SHARING_FIREWALL_HOLE_NEARBY_CONNECTIONS_FIREWALL_HOLE_H_
+#define CHROME_BROWSER_NEARBY_SHARING_FIREWALL_HOLE_NEARBY_CONNECTIONS_FIREWALL_HOLE_H_
+
+#include <memory>
+
+#include "ash/services/nearby/public/mojom/firewall_hole.mojom.h"
+
+namespace chromeos {
+class FirewallHole;
+}  // namespace chromeos
+
+// An implementation of the mojo interface representing a firewall hole for
+// Nearby Connections WifiLan TCP sockets. This implementation is essentially a
+// wrapper around a chromeos::FirewallHole.
+class NearbyConnectionsFirewallHole : public sharing::mojom::FirewallHole {
+ public:
+  explicit NearbyConnectionsFirewallHole(
+      std::unique_ptr<chromeos::FirewallHole> firewall_hole);
+  NearbyConnectionsFirewallHole(const NearbyConnectionsFirewallHole&) = delete;
+  NearbyConnectionsFirewallHole& operator=(
+      const NearbyConnectionsFirewallHole&) = delete;
+  ~NearbyConnectionsFirewallHole() override;
+
+ private:
+  std::unique_ptr<chromeos::FirewallHole> firewall_hole_;
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_FIREWALL_HOLE_NEARBY_CONNECTIONS_FIREWALL_HOLE_H_
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.cc b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.cc
new file mode 100644
index 0000000..3457305
--- /dev/null
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.cc
@@ -0,0 +1,51 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <string>
+
+#include "chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h"
+
+#include "ash/services/nearby/public/cpp/tcp_server_socket_port.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h"
+#include "chromeos/network/firewall_hole.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+
+NearbyConnectionsFirewallHoleFactory::NearbyConnectionsFirewallHoleFactory() =
+    default;
+
+NearbyConnectionsFirewallHoleFactory::~NearbyConnectionsFirewallHoleFactory() =
+    default;
+
+void NearbyConnectionsFirewallHoleFactory::OpenFirewallHole(
+    const ash::nearby::TcpServerSocketPort& port,
+    OpenFirewallHoleCallback callback) {
+  chromeos::FirewallHole::Open(
+      chromeos::FirewallHole::PortType::TCP, port.port(),
+      /*interface=*/std::string(),
+      base::BindOnce(
+          &NearbyConnectionsFirewallHoleFactory::OnFirewallHoleOpened,
+          weak_ptr_factory_.GetWeakPtr(), port, std::move(callback)));
+}
+
+void NearbyConnectionsFirewallHoleFactory::OnFirewallHoleOpened(
+    const ash::nearby::TcpServerSocketPort& port,
+    OpenFirewallHoleCallback callback,
+    std::unique_ptr<chromeos::FirewallHole> firewall_hole) {
+  if (!firewall_hole) {
+    LOG(ERROR) << "NearbyConnectionsFirewallHoleFactory::" << __func__
+               << ": Failed to open TCP firewall hole on port " << port.port();
+    std::move(callback).Run(/*firewall_hole=*/mojo::NullRemote());
+    return;
+  }
+
+  mojo::PendingRemote<sharing::mojom::FirewallHole> firewall_hole_remote;
+  firewall_hole_receivers_.Add(
+      std::make_unique<NearbyConnectionsFirewallHole>(std::move(firewall_hole)),
+      firewall_hole_remote.InitWithNewPipeAndPassReceiver());
+
+  std::move(callback).Run(std::move(firewall_hole_remote));
+}
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h
new file mode 100644
index 0000000..d52c981
--- /dev/null
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h
@@ -0,0 +1,54 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NEARBY_SHARING_FIREWALL_HOLE_NEARBY_CONNECTIONS_FIREWALL_HOLE_FACTORY_H_
+#define CHROME_BROWSER_NEARBY_SHARING_FIREWALL_HOLE_NEARBY_CONNECTIONS_FIREWALL_HOLE_FACTORY_H_
+
+#include <memory>
+
+#include "ash/services/nearby/public/mojom/firewall_hole.mojom.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/unique_receiver_set.h"
+
+namespace ash {
+namespace nearby {
+class TcpServerSocketPort;
+}  // namespace nearby
+}  // namespace ash
+
+namespace chromeos {
+class FirewallHole;
+}  // namespace chromeos
+
+// An implementation of the mojo service used to open firewall holes for Nearby
+// Connections WifiLan TCP sockets. This implementation is essentially a wrapper
+// around chromeos::FirewallHole::Open(). The lifetime of a firewall hole
+// mirrors the lifetime of the mojo remote provided by OpenFirewallHole(); the
+// corresponding mojo receivers are owned by |firewall_hole_receivers_|.
+class NearbyConnectionsFirewallHoleFactory
+    : public sharing::mojom::FirewallHoleFactory {
+ public:
+  NearbyConnectionsFirewallHoleFactory();
+  NearbyConnectionsFirewallHoleFactory(
+      const NearbyConnectionsFirewallHoleFactory&) = delete;
+  NearbyConnectionsFirewallHoleFactory& operator=(
+      const NearbyConnectionsFirewallHoleFactory&) = delete;
+  ~NearbyConnectionsFirewallHoleFactory() override;
+
+  void OpenFirewallHole(const ash::nearby::TcpServerSocketPort& port,
+                        OpenFirewallHoleCallback callback) override;
+
+ private:
+  void OnFirewallHoleOpened(
+      const ash::nearby::TcpServerSocketPort& port,
+      OpenFirewallHoleCallback callback,
+      std::unique_ptr<chromeos::FirewallHole> firewall_hole);
+
+  mojo::UniqueReceiverSet<sharing::mojom::FirewallHole>
+      firewall_hole_receivers_;
+  base::WeakPtrFactory<NearbyConnectionsFirewallHoleFactory> weak_ptr_factory_{
+      this};
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_FIREWALL_HOLE_NEARBY_CONNECTIONS_FIREWALL_HOLE_FACTORY_H_
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory_unittest.cc b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory_unittest.cc
new file mode 100644
index 0000000..edae9c6
--- /dev/null
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h"
+
+#include <memory>
+#include <string>
+
+#include "ash/services/nearby/public/cpp/tcp_server_socket_port.h"
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "chromeos/dbus/permission_broker/fake_permission_broker_client.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+uint16_t kPort = ash::nearby::TcpServerSocketPort::kMin + 1;
+
+void MoveFirewallHole(
+    base::RunLoop* run_loop,
+    mojo::PendingRemote<sharing::mojom::FirewallHole>* out_hole,
+    mojo::PendingRemote<sharing::mojom::FirewallHole> hole) {
+  *out_hole = std::move(hole);
+  run_loop->Quit();
+}
+
+class NearbyConnectionsFirewallHoleFactoryTest : public testing::Test {
+ public:
+  NearbyConnectionsFirewallHoleFactoryTest()
+      : port_(*ash::nearby::TcpServerSocketPort::FromUInt16(kPort)),
+        task_environment_(
+            base::test::SingleThreadTaskEnvironment::MainThreadType::UI) {}
+  ~NearbyConnectionsFirewallHoleFactoryTest() override = default;
+
+  void SetUp() override { chromeos::PermissionBrokerClient::InitializeFake(); }
+
+  void TearDown() override { chromeos::PermissionBrokerClient::Shutdown(); }
+
+  const ash::nearby::TcpServerSocketPort port_;
+  NearbyConnectionsFirewallHoleFactory factory_;
+
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+};
+
+TEST_F(NearbyConnectionsFirewallHoleFactoryTest, Success) {
+  base::RunLoop run_loop;
+  mojo::PendingRemote<sharing::mojom::FirewallHole> hole;
+  factory_.OpenFirewallHole(
+      port_, base::BindOnce(&MoveFirewallHole, &run_loop, &hole));
+  run_loop.Run();
+
+  EXPECT_TRUE(hole);
+  EXPECT_TRUE(chromeos::FakePermissionBrokerClient::Get()->HasTcpHole(
+      kPort, /*interface=*/std::string()));
+
+  // Destroy the PendingRemote, which will destroy the underlying FirewallHole.
+  hole.reset();
+  task_environment_.RunUntilIdle();
+  EXPECT_FALSE(chromeos::FakePermissionBrokerClient::Get()->HasTcpHole(
+      kPort, /*interface=*/std::string()));
+}
+
+TEST_F(NearbyConnectionsFirewallHoleFactoryTest, Failure) {
+  chromeos::FakePermissionBrokerClient::Get()->AddTcpDenyRule(
+      kPort,
+      /*interface=*/std::string());
+
+  base::RunLoop run_loop;
+  mojo::PendingRemote<sharing::mojom::FirewallHole> hole;
+  factory_.OpenFirewallHole(
+      port_, base::BindOnce(&MoveFirewallHole, &run_loop, &hole));
+  run_loop.Run();
+  EXPECT_FALSE(hole);
+}
+
+}  // namespace
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitions.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitions.java
index 461131c..a2797b5 100644
--- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitions.java
+++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitions.java
@@ -227,7 +227,7 @@
             map.put(ChannelId.PRICE_DROP,
                     PredefinedChannel.create(ChannelId.PRICE_DROP,
                             R.string.notification_category_price_drop,
-                            NotificationManager.IMPORTANCE_LOW, ChannelGroupId.GENERAL));
+                            NotificationManager.IMPORTANCE_DEFAULT, ChannelGroupId.GENERAL));
 
             // The security key notification channel will only appear for users
             // who use this feature.
diff --git a/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.cc b/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.cc
index 13eb055..1ddc3d4 100644
--- a/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.cc
+++ b/chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.cc
@@ -190,7 +190,7 @@
   prefs_->SetInteger(prefs::kPrefetchUsageOpenedCount, prefetch_opened_count_);
   prefs_->SetInteger(prefs::kPrefetchUsageMixedCount, prefetch_mixed_count_);
 
-  prefs_->CommitPendingWrite();
+  prefs_->SchedulePendingLossyWrites();
 }
 
 void OfflineMetricsCollectorImpl::SetTrackingFlag(bool* flag) {
diff --git a/chrome/browser/page_load_metrics/observers/core/CLS.md b/chrome/browser/page_load_metrics/observers/core/CLS.md
new file mode 100644
index 0000000..3139191
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/core/CLS.md
@@ -0,0 +1,96 @@
+# Cumulative Layout Shift
+
+[Cumulative Layout Shift](https://web.dev/cls) is a
+[Core Web Vital](https://web.dev/vitals) metric that reports the largest burst
+of layout shift scores for every unexpected layout shift that occurs during the
+entire lifespan of a page.
+
+This document details:
+* [Where it is computed in the renderer](#Computation-in-Renderer)
+* [How it is reported in trace events and web performance APIs](#Reporting-in-web-performance-APIs-and-trace-events)
+* [How values from different frames are merged](#Merging-multiple-frames)
+* [How it is reported to UKM/UMA](#Reporting-in-UKM-and-UMA)
+
+## Computation in Renderer
+
+Individual layout shifts are computed in the
+[`LayoutShiftTracker`](/third_party/blink/renderer/core/layout/layout_shift_tracker.cc)
+class.
+
+* The paint code calls `LayoutShiftTracker::NotifyBoxPrePaint()` and
+  `LayoutShiftTracker::NotifyTextPrePaint()` during prepaint to notify the class
+  of potential layout shifts.
+* The paint code calls `LayoutShiftTracker::NotifyPrePaintFinished()` to notify
+  the class when each frame's prepaint is finished so that the layout shift
+  score can be reported.
+* Layout shifts within 500ms of a user input should be ignored; other areas in
+  the chromium codebase that could cause such inputs call methods like
+  `LayoutShiftTracker::NotifyInput()` and `LayoutShiftTracker::NotifyScroll()`
+  to inform the class of these user inputs.
+
+### Debugging Renderer Computation
+
+The `LayoutShiftTracker` class has off-by-default logging which can help explain
+ the details of how layout shift computations are performed. You can use these
+ command line arguments to chromium to see the logs:
+
+`--enable-logging=stderr --vmodule=layout_shift*=1`
+
+There is a lot more helpful debugging info in the document
+[Debugging CLS](https://bit.ly/debug-cls).
+
+## Reporting in web performance APIs and trace events
+
+Individual layout shifts from the renderer are reported in the
+`LayoutShiftTracker::ReportShift()` method.
+
+* `LayoutShiftTracker::SubmitPerformanceEntry()` is called from `ReportShift`
+  and calls [`WindowPerformance::AddLayoutShiftEntry()`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/timing/window_performance.cc;drc=054e08864177603f17edbc111db7ebc8586906bd;bpv=0;bpt=0;l=621)
+  to add the layout shift entry to the performance timeline, which reports these
+  shifts via the
+  [Layout Instability API](https://wicg.github.io/layout-instability/).
+* Individual trace events are reported from `ReportShift` to the `loading`
+  category. Trace events have the name `LayoutShift`.
+* `ReportShift` also calls
+  [`LocalFrameClientImpl::DidObserveLayoutShift()`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/local_frame_client_impl.cc;l=730;drc=054e08864177603f17edbc111db7ebc8586906bd;bpv=1;bpt=1?q=metrics_render_frame_observer.cc&ss=chromium%2Fchromium%2Fsrc)
+  which kicks off reporting to the
+  [PageLoadMetricsObserver](/chrome/browser/page_load_metrics/observers/README.md)
+  so that the values can be reported in UMA and UKM. The reporting happens via a
+  call to
+  [`MetricsRenderFrameObserver::DidObserveLayoutShift()`](https://source.chromium.org/chromium/chromium/src/+/main:components/page_load_metrics/renderer/metrics_render_frame_observer.cc;l=145;bpv=1;bpt=1?q=metrics_render_frame_observer.cc&ss=chromium%2Fchromium%2Fsrc)
+  which then calls
+  [`PageTimingMetricsSender::DidObserveLayoutShift`()](https://source.chromium.org/chromium/chromium/src/+/main:components/page_load_metrics/renderer/page_timing_metrics_sender.cc;l=103;drc=054e08864177603f17edbc111db7ebc8586906bd?q=page_timing_metrics_sender.h&ss=chromium%2Fchromium%2Fsrc)
+  to ensure the data is sent via mojo IPC to the renderer.
+
+## Merging multiple frames
+
+In the renderer, individual frame layout shifts are assigned a weighting factor
+based on the percent of the viewport used by the frame in
+[`LayoutShiftTracker::SubframeWeightingFactor()`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/layout/layout_shift_tracker.cc;l=478;bpv=1;bpt=1).
+
+Weighted layout shifts from each frame are then reported to the browser in
+[`FrameRenderDataUpdate.new_layout_shifts`](https://source.chromium.org/chromium/chromium/src/+/main:components/page_load_metrics/common/page_load_metrics.mojom;drc=054e08864177603f17edbc111db7ebc8586906bd;bpv=1;bpt=1;l=310). The
+[`LayoutShiftNormalization`](/components/page_load_metrics/browser/layout_shift_normalization.cc)
+class manages the normalization of individual layout shifts into windows, so
+that the session window with the highest layout shifts can be reported. Layout
+shifts are added to the class from
+[`PageLoadMetricsUpdateDispatcher`](/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc).
+
+## Reporting in UKM and UMA
+
+All Core Web Vitals UKM are reported via
+[PageLoadMetricsObserver](/chrome/browser/page_load_metrics/observers/README.md).
+This ensures consistent reporting of only main frames, excluding error pages,
+etc.
+
+UKM for CLS are:
+* Most navigations:
+  `PageLoad.LayoutInstability.MaxCumulativeShiftScore.SessionWindow.Gap1000ms.Max5000ms`
+* BFCache navigations:
+  `HistoryNavigation.MaxCumulativeShiftScoreAfterBackForwardCacheRestore.SessionWindow.Gap1000ms.Max5000ms`
+
+UMA for CLS are:
+* Most navigations:
+  `PageLoad.LayoutInstability.MaxCumulativeShiftScore.SessionWindow.Gap1000ms.Max5000ms`
+* BFCache navigations:
+  `PageLoad.LayoutInstability.MaxCumulativeShiftScore.AfterBackForwardCacheRestore.SessionWindow.Gap1000ms.Max5000ms`
\ No newline at end of file
diff --git a/chrome/browser/payments/has_enrolled_instrument_browsertest.cc b/chrome/browser/payments/has_enrolled_instrument_browsertest.cc
index 3427e8c..d9fc7d0 100644
--- a/chrome/browser/payments/has_enrolled_instrument_browsertest.cc
+++ b/chrome/browser/payments/has_enrolled_instrument_browsertest.cc
@@ -2,29 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/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/test/payments/payment_request_platform_browsertest_base.h"
 #include "chrome/test/payments/personal_data_manager_test_util.h"
-#include "components/payments/core/features.h"
-#include "components/payments/core/journey_logger.h"
+#include "content/public/common/content_features.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace payments {
 namespace {
 
-class HasEnrolledInstrumentTest : public PaymentRequestPlatformBrowserTestBase {
+class HasEnrolledInstrumentBaseTest
+    : public PaymentRequestPlatformBrowserTestBase {
  public:
-  HasEnrolledInstrumentTest() = default;
+  HasEnrolledInstrumentBaseTest(const HasEnrolledInstrumentBaseTest&) = delete;
+  HasEnrolledInstrumentBaseTest& operator=(
+      const HasEnrolledInstrumentBaseTest&) = delete;
 
-  HasEnrolledInstrumentTest(const HasEnrolledInstrumentTest&) = delete;
-  HasEnrolledInstrumentTest& operator=(const HasEnrolledInstrumentTest&) =
-      delete;
-
-  ~HasEnrolledInstrumentTest() override = default;
+  ~HasEnrolledInstrumentBaseTest() override = default;
 
   void SetUpOnMainThread() override {
     PaymentRequestPlatformBrowserTestBase::SetUpOnMainThread();
@@ -33,31 +28,57 @@
 
   // Helper function to test that all variations of hasEnrolledInstrument()
   // returns |expected|.
-  void ExpectHasEnrolledInstrumentIs(bool expected) {
-    EXPECT_EQ(expected, content::EvalJs(GetActiveWebContents(),
-                                        "hasEnrolledInstrument()"));
-    EXPECT_EQ(expected,
-              content::EvalJs(GetActiveWebContents(),
-                              "hasEnrolledInstrument({requestShipping:true})"));
+  void ExpectHasEnrolledInstrumentIs(
+      bool expected,
+      const std::string& payment_method = "basic-card") {
     EXPECT_EQ(expected, content::EvalJs(
                             GetActiveWebContents(),
-                            "hasEnrolledInstrument({requestPayerEmail:true})"));
+                            content::JsReplace("hasEnrolledInstrument({}, $1)",
+                                               payment_method)));
+    EXPECT_EQ(
+        expected,
+        content::EvalJs(GetActiveWebContents(),
+                        content::JsReplace(
+                            "hasEnrolledInstrument({requestShipping:true}, $1)",
+                            payment_method)));
+    EXPECT_EQ(expected,
+              content::EvalJs(
+                  GetActiveWebContents(),
+                  content::JsReplace(
+                      "hasEnrolledInstrument({requestPayerEmail:true}, $1)",
+                      payment_method)));
   }
 
- private:
+ protected:
+  HasEnrolledInstrumentBaseTest() = default;
   base::test::ScopedFeatureList feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, NoCard) {
+class HasEnrolledInstrumentBasicCardTest
+    : public HasEnrolledInstrumentBaseTest {
+ public:
+  HasEnrolledInstrumentBasicCardTest() {
+    feature_list_.InitAndEnableFeature(features::kPaymentRequestBasicCard);
+  }
+
+  HasEnrolledInstrumentBasicCardTest(
+      const HasEnrolledInstrumentBasicCardTest&) = delete;
+  HasEnrolledInstrumentBasicCardTest& operator=(
+      const HasEnrolledInstrumentBasicCardTest&) = delete;
+
+  ~HasEnrolledInstrumentBasicCardTest() override = default;
+};
+
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest, NoCard) {
   ExpectHasEnrolledInstrumentIs(false);
 }
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, NoBillingAddress) {
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest, NoBillingAddress) {
   AddCreditCard(autofill::test::GetCreditCard());
   ExpectHasEnrolledInstrumentIs(true);
 }
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest,
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest,
                        HaveShippingNoBillingAddress) {
   CreateAndAddAutofillProfile();
   AddCreditCard(autofill::test::GetCreditCard());
@@ -65,14 +86,14 @@
   ExpectHasEnrolledInstrumentIs(true);
 }
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest,
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest,
                        HaveShippingAndBillingAddress) {
   CreateAndAddCreditCardForProfile(CreateAndAddAutofillProfile());
 
   ExpectHasEnrolledInstrumentIs(true);
 }
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, InvalidCardNumber) {
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest, InvalidCardNumber) {
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
   AddAutofillProfile(address);
   autofill::CreditCard card = CreatCreditCardForProfile(address);
@@ -83,7 +104,7 @@
   ExpectHasEnrolledInstrumentIs(false);
 }
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, ExpiredCard) {
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest, ExpiredCard) {
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
   AddAutofillProfile(address);
   autofill::CreditCard card = CreatCreditCardForProfile(address);
@@ -95,7 +116,7 @@
 
 // TODO(https://crbug.com/994799): Unify autofill data validation and returned
 // data across platforms.
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest,
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest,
                        HaveNoNameShippingAndBillingAddress) {
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
   address.SetRawInfo(autofill::ServerFieldType::NAME_FIRST, std::u16string());
@@ -113,7 +134,7 @@
   ExpectHasEnrolledInstrumentIs(true);
 }
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest,
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest,
                        HaveNoStreetShippingAndBillingAddress) {
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
   address.SetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_STREET_ADDRESS,
@@ -124,7 +145,7 @@
   ExpectHasEnrolledInstrumentIs(true);
 }
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, NoEmailAddress) {
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest, NoEmailAddress) {
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
   address.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS,
                      std::u16string());
@@ -134,7 +155,8 @@
   ExpectHasEnrolledInstrumentIs(true);
 }
 
-IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentTest, InvalidEmailAddress) {
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentBasicCardTest,
+                       InvalidEmailAddress) {
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
   address.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS,
                      u"this-is-not-a-valid-email-address");
@@ -144,5 +166,51 @@
   ExpectHasEnrolledInstrumentIs(true);
 }
 
+class HasEnrolledInstrumentPaymentHandlerTest
+    : public HasEnrolledInstrumentBaseTest {
+ public:
+  HasEnrolledInstrumentPaymentHandlerTest() {
+    feature_list_.InitAndDisableFeature(features::kPaymentRequestBasicCard);
+  }
+
+  HasEnrolledInstrumentPaymentHandlerTest(
+      const HasEnrolledInstrumentPaymentHandlerTest&) = delete;
+  HasEnrolledInstrumentPaymentHandlerTest& operator=(
+      const HasEnrolledInstrumentPaymentHandlerTest&) = delete;
+
+  ~HasEnrolledInstrumentPaymentHandlerTest() override = default;
+};
+
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentPaymentHandlerTest,
+                       FalseWithoutPaymentHandler) {
+  ExpectHasEnrolledInstrumentIs(false);
+}
+
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentPaymentHandlerTest,
+                       FalseWithPaymentHandlerAvailableToInstallJustInTime) {
+  std::string payment_method =
+      https_server()->GetURL("nickpay.com", "/nickpay.com/pay").spec();
+
+  ExpectHasEnrolledInstrumentIs(false, payment_method);
+}
+
+IN_PROC_BROWSER_TEST_F(HasEnrolledInstrumentPaymentHandlerTest,
+                       TrueWithInstalledPaymentHandler) {
+  std::string payment_handler_host = "nickpay.com";
+  NavigateTo(payment_handler_host, "/payment_handler_installer.html");
+  std::string sw_url = https_server()
+                           ->GetURL(payment_handler_host, "/nickpay.com/app.js")
+                           .spec();
+  std::string payment_method =
+      https_server()->GetURL(payment_handler_host, "/nickpay.com/pay").spec();
+  EXPECT_EQ("success",
+            content::EvalJs(GetActiveWebContents(),
+                            content::JsReplace("install($1, [$2])", sw_url,
+                                               payment_method)));
+  NavigateTo("/has_enrolled_instrument.html");
+
+  ExpectHasEnrolledInstrumentIs(true, payment_method);
+}
+
 }  // namespace
 }  // namespace payments
diff --git a/chrome/browser/profiles/profile_window.cc b/chrome/browser/profiles/profile_window.cc
index 4ad2a830..90060df3 100644
--- a/chrome/browser/profiles/profile_window.cc
+++ b/chrome/browser/profiles/profile_window.cc
@@ -85,9 +85,8 @@
 }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
-// Called in profiles::LoadProfileAsync once profile is loaded. It runs
-// |callback| if it isn't null.
-void ProfileLoadedCallback(ProfileManager::CreateCallback callback,
+// Helper function to run a callback on a profile once it's initialized.
+void ProfileLoadedCallback(base::OnceCallback<void(Profile*)>& callback,
                            Profile* profile,
                            Profile::CreateStatus status) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -95,26 +94,10 @@
   if (status != Profile::CREATE_STATUS_INITIALIZED)
     return;
 
-  if (!callback.is_null())
-    callback.Run(profile, Profile::CREATE_STATUS_INITIALIZED);
-}
-
-// Calls `profiles::OpenBrowserWindowForProfile()` only if the profile is
-// initialized, and moves the callback only in this case.
-void OpenBrowserWindowForProfileHelper(
-    base::OnceCallback<void(Profile*)>& callback,
-    bool always_create,
-    Profile* profile,
-    Profile::CreateStatus status) {
-  if (status != Profile::CREATE_STATUS_INITIALIZED)
-    return;
-
   // This function is called with `CREATE_STATUS_INITIALIZED` at most once, so
   // it is fine to move the callback.
-  profiles::OpenBrowserWindowForProfile(std::move(callback), always_create,
-                                        /*is_new_profile=*/false,
-                                        /*unblock_extensions=*/false, profile,
-                                        status);
+  if (callback)
+    std::move(callback).Run(profile);
 }
 
 }  // namespace
@@ -163,15 +146,10 @@
                                  bool always_create,
                                  bool is_new_profile,
                                  bool unblock_extensions,
-                                 Profile* profile,
-                                 Profile::CreateStatus status) {
+                                 Profile* profile) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  TRACE_EVENT2("browser", "OpenBrowserWindowForProfile", "profile_path",
-               profile->GetPath().AsUTF8Unsafe(), "status", status);
-
-  if (status != Profile::CREATE_STATUS_INITIALIZED)
-    return;
-
+  TRACE_EVENT1("browser", "OpenBrowserWindowForProfile", "profile_path",
+               profile->GetPath().AsUTF8Unsafe());
   chrome::startup::IsProcessStartup process_startup =
       chrome::startup::IsProcessStartup::kNo;
   chrome::startup::IsFirstRun is_first_run = chrome::startup::IsFirstRun::kNo;
@@ -245,21 +223,24 @@
 #if !defined(OS_ANDROID)
 
 void LoadProfileAsync(const base::FilePath& path,
-                      ProfileManager::CreateCallback callback) {
+                      base::OnceCallback<void(Profile*)> callback) {
   g_browser_process->profile_manager()->CreateProfileAsync(
-      path, base::BindRepeating(&ProfileLoadedCallback, callback));
+      path, base::BindRepeating(&ProfileLoadedCallback,
+                                base::OwnedRef(std::move(callback))));
 }
 
 void SwitchToProfile(const base::FilePath& path,
                      bool always_create,
                      base::OnceCallback<void(Profile*)> callback) {
+  base::OnceCallback<void(Profile*)> open_browser_callback =
+      base::BindOnce(&profiles::OpenBrowserWindowForProfile,
+                     std::move(callback), always_create,
+                     /*is_new_profile=*/false,
+                     /*unblock_extensions=*/false);
   g_browser_process->profile_manager()->CreateProfileAsync(
       path,
-      base::BindRepeating(
-          &OpenBrowserWindowForProfileHelper,
-          // `OpenBrowserWindowForProfileHelper` is called multiple times, but
-          // `callback` is only called when the profile is initialized.
-          base::OwnedRef(std::move(callback)), always_create));
+      base::BindRepeating(&ProfileLoadedCallback,
+                          base::OwnedRef(std::move(open_browser_callback))));
 }
 
 void SwitchToGuestProfile(base::OnceCallback<void(Profile*)> callback) {
diff --git a/chrome/browser/profiles/profile_window.h b/chrome/browser/profiles/profile_window.h
index 358c2a6..2d56130 100644
--- a/chrome/browser/profiles/profile_window.h
+++ b/chrome/browser/profiles/profile_window.h
@@ -51,13 +51,12 @@
                                  bool always_create,
                                  bool is_new_profile,
                                  bool unblock_extensions,
-                                 Profile* profile,
-                                 Profile::CreateStatus status);
+                                 Profile* profile);
 
 // Loads the specified profile given by |path| asynchronously. Once profile is
 // loaded and initialized it runs |callback| if it isn't null.
 void LoadProfileAsync(const base::FilePath& path,
-                      ProfileManager::CreateCallback callback);
+                      base::OnceCallback<void(Profile*)> callback);
 
 // Opens a Browser with the specified profile given by |path|.
 // If |always_create| is true then a new window is created
diff --git a/chrome/browser/profiles/profile_window_browsertest.cc b/chrome/browser/profiles/profile_window_browsertest.cc
index 3769923..bf74e4a 100644
--- a/chrome/browser/profiles/profile_window_browsertest.cc
+++ b/chrome/browser/profiles/profile_window_browsertest.cc
@@ -307,9 +307,8 @@
 IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, OpenBrowserWindowForProfile) {
   Profile* profile = browser()->profile();
   size_t num_browsers = BrowserList::GetInstance()->size();
-  profiles::OpenBrowserWindowForProfile(
-      base::OnceCallback<void(Profile*)>(), true, false, false, profile,
-      Profile::CreateStatus::CREATE_STATUS_INITIALIZED);
+  profiles::OpenBrowserWindowForProfile(base::OnceCallback<void(Profile*)>(),
+                                        true, false, false, profile);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(num_browsers + 1, BrowserList::GetInstance()->size());
   EXPECT_FALSE(ProfilePicker::IsOpen());
@@ -337,9 +336,8 @@
   base::RunLoop run_loop;
   ProfilePicker::AddOnProfilePickerOpenedCallbackForTesting(
       run_loop.QuitClosure());
-  profiles::OpenBrowserWindowForProfile(
-      base::OnceCallback<void(Profile*)>(), true, false, false, profile,
-      Profile::CreateStatus::CREATE_STATUS_INITIALIZED);
+  profiles::OpenBrowserWindowForProfile(base::OnceCallback<void(Profile*)>(),
+                                        true, false, false, profile);
   run_loop.Run();
   EXPECT_EQ(num_browsers, BrowserList::GetInstance()->size());
   EXPECT_TRUE(ProfilePicker::IsOpen());
diff --git a/chrome/browser/resources/access_code_cast/access_code_cast.html b/chrome/browser/resources/access_code_cast/access_code_cast.html
index 16853e81..176cd971 100644
--- a/chrome/browser/resources/access_code_cast/access_code_cast.html
+++ b/chrome/browser/resources/access_code_cast/access_code_cast.html
@@ -33,10 +33,12 @@
   <div slot="body">
     <div id="codeInputView">
       <c2c-code-input length="6" value="" id="codeInput"></c2c-code-input>
-      <cr-button on-click="switchToQrInput" class="center text-button">
-        <iron-icon class="button-image" icon="cr:videocam"></iron-icon>
-        $i18n{useCamera}
-      </cr-button>
+      <template is="dom-if" if="[[qrScannerEnabled]]">
+        <cr-button on-click="switchToQrInput" class="center text-button">
+          <iron-icon class="button-image" icon="cr:videocam"></iron-icon>
+          $i18n{useCamera}
+        </cr-button>
+      </template>
     </div>
     <div id="qrInputView">
       <div>Camera input view</div>
diff --git a/chrome/browser/resources/access_code_cast/access_code_cast.ts b/chrome/browser/resources/access_code_cast/access_code_cast.ts
index b40c6f8..0ee49ecd 100644
--- a/chrome/browser/resources/access_code_cast/access_code_cast.ts
+++ b/chrome/browser/resources/access_code_cast/access_code_cast.ts
@@ -56,6 +56,7 @@
   private static readonly ACCESS_CODE_LENGTH = 6;
   private accessCode: string;
   private state: PageState;
+  private qrScannerEnabled: boolean;
 
   constructor() {
     super();
@@ -63,6 +64,9 @@
     this.router = BrowserProxy.getInstance().callbackRouter;
 
     this.accessCode = '';
+    BrowserProxy.getInstance().isQrScanningAvailable().then((available) => {
+      this.qrScannerEnabled = available;
+    });
 
     window.onblur = () => {
       this.close();
@@ -89,7 +93,7 @@
   }
 
   close() {
-    chrome.send('dialogClose');
+    BrowserProxy.getInstance().closeDialog();
   }
 
   switchToCodeInput() {
diff --git a/chrome/browser/resources/access_code_cast/browser_proxy.ts b/chrome/browser/resources/access_code_cast/browser_proxy.ts
index d26bc1e0..980eb96 100644
--- a/chrome/browser/resources/access_code_cast/browser_proxy.ts
+++ b/chrome/browser/resources/access_code_cast/browser_proxy.ts
@@ -2,8 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import './strings.m.js';
+
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+
 import {PageCallbackRouter, PageHandlerFactory, PageHandlerRemote} from './access_code_cast.mojom-webui.js';
 
+declare const chrome: {
+  send(message: string): void;
+  getVariableValue(variable: string): string;
+};
+
 export class BrowserProxy {
   callbackRouter: PageCallbackRouter;
   handler: PageHandlerRemote;
@@ -19,6 +28,38 @@
         this.handler.$.bindNewPipeAndPassReceiver());
   }
 
+  closeDialog() {
+    chrome.send('dialogClose');
+  }
+
+  getDialogArgs() {
+    return JSON.parse(chrome.getVariableValue('dialogArguments'));
+  }
+
+  isDialog() {
+    return chrome.getVariableValue('dialogArguments').length > 0;
+  }
+
+  isBarcodeApiAvailable() {
+    return ('BarcodeDetector' in window);
+  }
+
+  async isQrScanningAvailable() {
+    return loadTimeData.getBoolean('qrScannerEnabled')
+        && this.isBarcodeApiAvailable()
+        && (await this.isCameraAvailable());
+  }
+
+  async isCameraAvailable() {
+    const devices = await navigator.mediaDevices.enumerateDevices();
+    for (const device of devices) {
+      if (device.kind === 'videoinput') {
+        return true;
+      }
+    }
+    return false;
+  }
+
   static getInstance(): BrowserProxy {
     return instance || (instance = new BrowserProxy());
   }
diff --git a/chrome/browser/resources/chromeos/login/components/gaia_dialog.html b/chrome/browser/resources/chromeos/login/components/gaia_dialog.html
index d03e441..5020b53 100644
--- a/chrome/browser/resources/chromeos/login/components/gaia_dialog.html
+++ b/chrome/browser/resources/chromeos/login/components/gaia_dialog.html
@@ -75,13 +75,22 @@
       #saml-notice-container,
       #saml-footer-container {
         align-items: center;
-        background: var(--google-grey-100);
+        background: white;
         box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.17);
         display: flex;
-        height: 44px;
         min-height: 0;
       }
 
+      #saml-notice-container {
+        border-bottom: 1px solid var(--google-grey-200);
+        height: 44px;
+      }
+
+      #saml-footer-container {
+        border-top: 1px solid var(--google-grey-200);
+        height: 58px;
+      }
+
       #saml-notice-recording-indicator {
         padding-inline-end: 10px;
         padding-inline-start: 10px;
@@ -92,8 +101,6 @@
       }
 
       #signin-frame {
-        border-top-left-radius: 4px;
-        border-top-right-radius: 4px;
         display: flex;
         overflow: hidden;
         /* Position relative is needed for proper size calculation of
@@ -121,6 +128,11 @@
         color: var(--google-red-600);
         text-align: center;
       }
+
+      #change-account {
+        padding-inline-end: 8px;
+        padding-inline-start: 8px;
+      }
     </style>
     <link rel="stylesheet" href="oobe_popup_overlay.css">
     <!-- As this dialog have pre-loading logic that require access to elements,
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_fragment_shared_css.html b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_fragment_shared_css.html
index 5c5069ab..95f67ae 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_fragment_shared_css.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_fragment_shared_css.html
@@ -60,7 +60,7 @@
 
     @media (prefers-color-scheme: dark) {
       .headline {
-        color: white;
+        color: var(--google-grey-200);
       }
     }
 
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.ts
index c5bc2a4..69e5712 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.ts
@@ -177,6 +177,7 @@
         PrivacyReviewStep.MSBB,
         {
           nextStep: PrivacyReviewStep.CLEAR_ON_EXIT,
+          previousStep: PrivacyReviewStep.WELCOME,
           isAvailable: () => true,
         },
       ],
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_welcome_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_welcome_fragment.html
index 59ca975..39f565c 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_welcome_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_welcome_fragment.html
@@ -10,7 +10,7 @@
     flex: 1;
     flex-direction: column;
     justify-content: space-between;
-    padding: 36px 120px var(--cr-section-padding) 120px;
+    padding: 36px 116px var(--cr-section-padding) 116px;
     text-align: center;
   }
 
diff --git a/chrome/browser/resources/tab_search/tab_group_color_helper.ts b/chrome/browser/resources/tab_search/tab_group_color_helper.ts
index 990aa577..ad2c529 100644
--- a/chrome/browser/resources/tab_search/tab_group_color_helper.ts
+++ b/chrome/browser/resources/tab_search/tab_group_color_helper.ts
@@ -15,6 +15,7 @@
   [Color.kPink, 'pink'],
   [Color.kPurple, 'purple'],
   [Color.kCyan, 'cyan'],
+  [Color.kOrange, 'orange'],
 ]);
 
 export function colorName(color: Color): string {
diff --git a/chrome/browser/resources/tab_search/tab_group_shared_vars.html b/chrome/browser/resources/tab_search/tab_group_shared_vars.html
index 9f09068..6bf17f6907 100644
--- a/chrome/browser/resources/tab_search/tab_group_shared_vars.html
+++ b/chrome/browser/resources/tab_search/tab_group_shared_vars.html
@@ -34,6 +34,10 @@
       --google-yellow-300: rgb(var(--google-yellow-300-rgb));
       --google-yellow-900-rgb: 227, 116, 0; /* #e37400 */
       --google-yellow-900: rgb(var(--google-yellow-900-rgb));
+      --google-orange-300-rgb:  252, 173, 112; /* #fcad70 */
+      --google-orange-300:  rgb(var(--google-orange-300-rgb));
+      --google-orange-400-rgb:  250, 144, 62; /* #fa903e */
+      --google-orange-400:  rgb(var(--google-orange-400-rgb));
 
       --tab-group-color-grey: var(--google-grey-700);
       --tab-group-color-blue: var(--google-blue-600);
@@ -43,6 +47,7 @@
       --tab-group-color-pink: var(--google-pink-700);
       --tab-group-color-purple: var(--google-purple-600);
       --tab-group-color-cyan: var(--google-cyan-900);
+      --tab-group-color-orange: var(--google-orange-400);
     }
 
     @media (prefers-color-scheme: dark) {
@@ -55,6 +60,7 @@
         --tab-group-color-pink: var(--google-pink-300);
         --tab-group-color-purple: var(--google-purple-200);
         --tab-group-color-cyan: var(--google-cyan-300);
+        --tab-group-color-orange: var(--google-orange-300);
       }
     }
   </style>
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
index a8f015aa..e2c0a8c 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -235,14 +235,20 @@
   bool safe_browsing_enabled =
       profile && IsSafeBrowsingEnabled(*profile->GetPrefs());
   auto settings = DeepScanningRequest::ShouldUploadBinary(item);
+  bool report_only_scan =
+      base::FeatureList::IsEnabled(kConnectorsScanningReportOnlyUI) &&
+      settings.has_value() &&
+      settings.value().block_until_verdict ==
+          enterprise_connectors::BlockUntilVerdict::NO_BLOCK;
 
   if (base::FeatureList::IsEnabled(kSafeBrowsingEnterpriseCsd) &&
       base::FeatureList::IsEnabled(
           kSafeBrowsingDisableConsumerCsdForEnterprise) &&
-      settings.has_value()) {
+      settings.has_value() && !report_only_scan) {
     // Since this branch implies that the CSD check is done through the deep
     // scanning request and not with a consumer check, the pre-deep scanning
-    // DownloadCheckResult is considered UNKNOWN.
+    // DownloadCheckResult is considered UNKNOWN. This shouldn't trigger on
+    // report-only scans to avoid skipping the consumer check.
     UploadForDeepScanning(item, std::move(callback),
                           DeepScanningRequest::DeepScanTrigger::TRIGGER_POLICY,
                           DownloadCheckResult::UNKNOWN,
@@ -255,9 +261,9 @@
     return true;
   }
 
-  // TODO(https://crbug.com/1165815): Remove this check once the enterpise CSD
-  // check has fully launched.
   if (settings.has_value()) {
+    DCHECK(report_only_scan);
+    DCHECK(!safe_browsing_enabled);
     // Since this branch implies that Safe Browsing is disabled, the pre-deep
     // scanning DownloadCheckResult is considered UNKNOWN.
     UploadForDeepScanning(item, std::move(callback),
diff --git a/chrome/browser/segmentation_platform/chrome_browser_main_extra_parts_segmentation_platform.cc b/chrome/browser/segmentation_platform/chrome_browser_main_extra_parts_segmentation_platform.cc
index 6b87421..9a567e6a 100644
--- a/chrome/browser/segmentation_platform/chrome_browser_main_extra_parts_segmentation_platform.cc
+++ b/chrome/browser/segmentation_platform/chrome_browser_main_extra_parts_segmentation_platform.cc
@@ -12,7 +12,13 @@
 #include "components/segmentation_platform/public/features.h"
 #include "components/segmentation_platform/public/segmentation_platform_service.h"
 
-void ChromeBrowserMainExtraPartsSegmentationPlatform::PostProfileInit() {
+void ChromeBrowserMainExtraPartsSegmentationPlatform::PostProfileInit(
+    Profile* profile,
+    bool is_initial_profile) {
+  // The setup below is intended to run for only the initial profile.
+  if (!is_initial_profile)
+    return;
+
   Profile* last_used_profile =
       g_browser_process->profile_manager()->GetLastUsedProfileIfLoaded();
   if (!last_used_profile || last_used_profile->IsOffTheRecord())
diff --git a/chrome/browser/segmentation_platform/chrome_browser_main_extra_parts_segmentation_platform.h b/chrome/browser/segmentation_platform/chrome_browser_main_extra_parts_segmentation_platform.h
index 783283c7..74bd6e2 100644
--- a/chrome/browser/segmentation_platform/chrome_browser_main_extra_parts_segmentation_platform.h
+++ b/chrome/browser/segmentation_platform/chrome_browser_main_extra_parts_segmentation_platform.h
@@ -12,7 +12,7 @@
  public:
   ChromeBrowserMainExtraPartsSegmentationPlatform() = default;
 
-  void PostProfileInit() override;
+  void PostProfileInit(Profile* profile, bool is_initial_profile) override;
 };
 
 #endif  // CHROME_BROWSER_SEGMENTATION_PLATFORM_CHROME_BROWSER_MAIN_EXTRA_PARTS_SEGMENTATION_PLATFORM_H_
diff --git a/chrome/browser/support_tool/ash/ui_hierarchy_data_collector.cc b/chrome/browser/support_tool/ash/ui_hierarchy_data_collector.cc
index 2208e53..0d243ac 100644
--- a/chrome/browser/support_tool/ash/ui_hierarchy_data_collector.cc
+++ b/chrome/browser/support_tool/ash/ui_hierarchy_data_collector.cc
@@ -15,10 +15,13 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/task/post_task.h"
+#include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/support_tool/data_collector.h"
 #include "components/feedback/pii_types.h"
+#include "components/feedback/redaction_tool.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/re2/src/re2/re2.h"
 #include "third_party/re2/src/re2/stringpiece.h"
@@ -104,7 +107,9 @@
 }
 
 void UiHierarchyDataCollector::CollectDataAndDetectPII(
-    DataCollectorDoneCallback on_data_collected_callback) {
+    DataCollectorDoneCallback on_data_collected_callback,
+    scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
+    scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   UIHierarchyData ui_hierarchy_data = CollectUiHierarchyData();
   InsertIntoPIIMap(ui_hierarchy_data.window_titles);
diff --git a/chrome/browser/support_tool/ash/ui_hierarchy_data_collector.h b/chrome/browser/support_tool/ash/ui_hierarchy_data_collector.h
index 411df35..74dd75b 100644
--- a/chrome/browser/support_tool/ash/ui_hierarchy_data_collector.h
+++ b/chrome/browser/support_tool/ash/ui_hierarchy_data_collector.h
@@ -9,9 +9,12 @@
 
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
 #include "chrome/browser/support_tool/data_collector.h"
 #include "components/feedback/pii_types.h"
+#include "components/feedback/redaction_tool.h"
 
 struct UIHierarchyData {
   UIHierarchyData(std::vector<std::string> window_titles, std::string data);
@@ -47,7 +50,10 @@
   const PIIMap& GetDetectedPII() override;
 
   void CollectDataAndDetectPII(
-      DataCollectorDoneCallback on_data_collected_callback) override;
+      DataCollectorDoneCallback on_data_collected_callback,
+      scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
+      scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container)
+      override;
 
   void ExportCollectedDataWithPII(
       std::set<feedback::PIIType> pii_types_to_keep,
diff --git a/chrome/browser/support_tool/ash/ui_hierarchy_data_collector_browsertest.cc b/chrome/browser/support_tool/ash/ui_hierarchy_data_collector_browsertest.cc
index f70356e..6cd4742 100644
--- a/chrome/browser/support_tool/ash/ui_hierarchy_data_collector_browsertest.cc
+++ b/chrome/browser/support_tool/ash/ui_hierarchy_data_collector_browsertest.cc
@@ -81,7 +81,9 @@
   base::test::TestFuture<absl::optional<SupportToolError>>
       test_future_collect_data;
   data_collector.CollectDataAndDetectPII(
-      test_future_collect_data.GetCallback());
+      test_future_collect_data.GetCallback(),
+      /*task_runner_for_redaction_tool=*/nullptr,
+      /*redaction_tool_container=*/nullptr);
   absl::optional<SupportToolError> error = test_future_collect_data.Get();
   EXPECT_EQ(error, absl::nullopt);
 
diff --git a/chrome/browser/support_tool/data_collector.h b/chrome/browser/support_tool/data_collector.h
index b4681b9..8489373f 100644
--- a/chrome/browser/support_tool/data_collector.h
+++ b/chrome/browser/support_tool/data_collector.h
@@ -12,7 +12,10 @@
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/sequenced_task_runner.h"
 #include "components/feedback/pii_types.h"
+#include "components/feedback/redaction_tool.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 // The error code that a Support Tool component can return.
@@ -22,6 +25,7 @@
   kTestDataCollectorError,
   kDataExportTempDirCreationFailed,
   kDataExportCreateArchiveFailed,
+  kSystemLogSourceFetchFailed,
 };
 
 using PIIMap = std::map<feedback::PIIType, std::set<std::string>>;
@@ -47,10 +51,16 @@
   virtual const PIIMap& GetDetectedPII() = 0;
 
   // Collects all data that can be collected and detects the PII in the
-  // collected data. `on_data_collected_callback` won't be run if the
-  // DataCollector instance is deleted.
+  // collected data. DataCollector may use feedback::RedactionTool of
+  // `redaction_tool_container` on `task_runner_for_redaction_tool` for PII
+  // detection or implement their own PII detection functions.
+  // `on_data_collected_callback` won't be run if the DataCollector instance is
+  // deleted.
   virtual void CollectDataAndDetectPII(
-      DataCollectorDoneCallback on_data_collected_callback) = 0;
+      DataCollectorDoneCallback on_data_collected_callback,
+      scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
+      scoped_refptr<feedback::RedactionToolContainer>
+          redaction_tool_container) = 0;
 
   // Masks all PII found in the collected data except `pii_types_to_keep`.
   // Exports the collected data into file(s) in `target_directory`. Calls
diff --git a/chrome/browser/support_tool/support_tool_handler.cc b/chrome/browser/support_tool/support_tool_handler.cc
index 2099fbb..0a73821 100644
--- a/chrome/browser/support_tool/support_tool_handler.cc
+++ b/chrome/browser/support_tool/support_tool_handler.cc
@@ -20,6 +20,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/strings/string_util.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/task_traits.h"
@@ -27,6 +28,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/support_tool/data_collector.h"
 #include "components/feedback/pii_types.h"
+#include "components/feedback/redaction_tool.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/zlib/google/zip.h"
 
@@ -53,7 +55,16 @@
   return temp_dir.Take();
 }
 
-SupportToolHandler::SupportToolHandler() = default;
+SupportToolHandler::SupportToolHandler()
+    : task_runner_for_redaction_tool_(
+          base::ThreadPool::CreateSequencedTaskRunner(
+              {base::TaskPriority::USER_VISIBLE,
+               base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})),
+      redaction_tool_container_(
+          base::MakeRefCounted<feedback::RedactionToolContainer>(
+              task_runner_for_redaction_tool_,
+              nullptr)) {}
+
 SupportToolHandler::~SupportToolHandler() {
   CleanUp();
 }
@@ -95,9 +106,17 @@
                      weak_ptr_factory_.GetWeakPtr()));
 
   for (auto& data_collector : data_collectors_) {
-    data_collector->CollectDataAndDetectPII(base::BindOnce(
-        &SupportToolHandler::OnDataCollected, weak_ptr_factory_.GetWeakPtr(),
-        collect_data_barrier_closure));
+    // DataCollectors will use `redaction_tool_container_` on
+    // `task_runner_for_redaction_tool_` to redact PII from the collected logs.
+    // All DataCollectors will use the same RedactionTool instance on the same
+    // task runner as we need to replace the same PII data with the same
+    // place-holder strings (that are stored in RedactionTool instance's data
+    // member) in all collected logs to avoid confusing the reader.
+    data_collector->CollectDataAndDetectPII(
+        base::BindOnce(&SupportToolHandler::OnDataCollected,
+                       weak_ptr_factory_.GetWeakPtr(),
+                       collect_data_barrier_closure),
+        task_runner_for_redaction_tool_, redaction_tool_container_);
   }
 }
 
diff --git a/chrome/browser/support_tool/support_tool_handler.h b/chrome/browser/support_tool/support_tool_handler.h
index b5907594..04a54c4 100644
--- a/chrome/browser/support_tool/support_tool_handler.h
+++ b/chrome/browser/support_tool/support_tool_handler.h
@@ -12,10 +12,14 @@
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
 #include "chrome/browser/support_tool/data_collector.h"
 #include "components/feedback/pii_types.h"
+#include "components/feedback/redaction_tool.h"
+#include "components/feedback/system_logs/system_logs_source.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 using SupportToolDataCollectedCallback =
@@ -140,6 +144,11 @@
   // data export is done or on destruction of the SupportToolHandler instance if
   // it hasn't been removed before.
   base::FilePath temp_dir_;
+  // SequencedTaskRunner and RedactionToolContainer for the data collectors that
+  // will need to use feedback::RedactionTool for masking PII from the collected
+  // logs.
+  scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool_;
+  scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container_;
   base::WeakPtrFactory<SupportToolHandler> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/support_tool/support_tool_handler_unittest.cc b/chrome/browser/support_tool/support_tool_handler_unittest.cc
index 76188ad..13a82e8 100644
--- a/chrome/browser/support_tool/support_tool_handler_unittest.cc
+++ b/chrome/browser/support_tool/support_tool_handler_unittest.cc
@@ -53,7 +53,10 @@
   const PIIMap& GetDetectedPII() override { return pii_map_; }
 
   void CollectDataAndDetectPII(
-      DataCollectorDoneCallback on_data_collected_callback) override {
+      DataCollectorDoneCallback on_data_collected_callback,
+      scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
+      scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container)
+      override {
     // Add fake PII for testing and return error to the callback if required.
     PrepareDataCollectionOutput(std::move(on_data_collected_callback));
   }
diff --git a/chrome/browser/support_tool/system_log_source_data_collector_adaptor.cc b/chrome/browser/support_tool/system_log_source_data_collector_adaptor.cc
new file mode 100644
index 0000000..6fd0158
--- /dev/null
+++ b/chrome/browser/support_tool/system_log_source_data_collector_adaptor.cc
@@ -0,0 +1,110 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/support_tool/system_log_source_data_collector_adaptor.h"
+
+#include <algorithm>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/check.h"
+#include "base/location.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/sequenced_task_runner.h"
+#include "chrome/browser/support_tool/data_collector.h"
+#include "components/feedback/feedback_common.h"
+#include "components/feedback/pii_types.h"
+#include "components/feedback/redaction_tool.h"
+#include "components/feedback/system_logs/system_logs_source.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace {
+
+// Detects PII sensitive data that `system_logs_response` contains and returns
+// the map of detected data.
+PIIMap DetectPII(
+    system_logs::SystemLogsResponse* system_logs_response,
+    scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container) {
+  DCHECK(system_logs_response);
+  feedback::RedactionTool* redaction_tool = redaction_tool_container->Get();
+  PIIMap detected_pii;
+  // Detect PII in all entries in `system_logs_response` and add the detected
+  // PII to `detected_pii`.
+  for (const auto& entry : *system_logs_response) {
+    PIIMap pii_in_logs = redaction_tool->Detect(entry.second);
+    for (auto& pii_data : pii_in_logs) {
+      detected_pii[pii_data.first].insert(pii_data.second.begin(),
+                                          pii_data.second.end());
+    }
+  }
+  return detected_pii;
+}
+
+}  // namespace
+
+SystemLogSourceDataCollectorAdaptor::SystemLogSourceDataCollectorAdaptor(
+    std::string description,
+    std::unique_ptr<system_logs::SystemLogsSource> log_source)
+    : description_(description), log_source_(std::move(log_source)) {}
+
+SystemLogSourceDataCollectorAdaptor::~SystemLogSourceDataCollectorAdaptor() =
+    default;
+
+std::string SystemLogSourceDataCollectorAdaptor::GetName() const {
+  return log_source_->source_name();
+}
+
+std::string SystemLogSourceDataCollectorAdaptor::GetDescription() const {
+  return description_;
+}
+
+const PIIMap& SystemLogSourceDataCollectorAdaptor::GetDetectedPII() {
+  return pii_map_;
+}
+
+void SystemLogSourceDataCollectorAdaptor::CollectDataAndDetectPII(
+    DataCollectorDoneCallback on_data_collected_callback,
+    scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
+    scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  log_source_->Fetch(base::BindOnce(
+      &SystemLogSourceDataCollectorAdaptor::OnDataFetched,
+      weak_ptr_factory_.GetWeakPtr(), std::move(on_data_collected_callback),
+      task_runner_for_redaction_tool, redaction_tool_container));
+}
+
+void SystemLogSourceDataCollectorAdaptor::OnDataFetched(
+    DataCollectorDoneCallback on_data_collected_callback,
+    scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
+    scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container,
+    std::unique_ptr<system_logs::SystemLogsResponse> system_logs_response) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  system_logs_response_ = std::move(system_logs_response);
+  task_runner_for_redaction_tool->PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(&DetectPII, system_logs_response_.get(),
+                     redaction_tool_container),
+      base::BindOnce(&SystemLogSourceDataCollectorAdaptor::OnPIIDetected,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(on_data_collected_callback)));
+}
+
+void SystemLogSourceDataCollectorAdaptor::OnPIIDetected(
+    DataCollectorDoneCallback on_data_collected_callback,
+    PIIMap detected_pii) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  pii_map_ = std::move(detected_pii);
+  std::move(on_data_collected_callback).Run(/*error_code=*/absl::nullopt);
+}
+
+void SystemLogSourceDataCollectorAdaptor::ExportCollectedDataWithPII(
+    std::set<feedback::PIIType> pii_types_to_keep,
+    base::FilePath target_directory,
+    DataCollectorDoneCallback on_exported_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Will add implementation of this function in the follow-up CL.
+}
diff --git a/chrome/browser/support_tool/system_log_source_data_collector_adaptor.h b/chrome/browser/support_tool/system_log_source_data_collector_adaptor.h
new file mode 100644
index 0000000..4befdba
--- /dev/null
+++ b/chrome/browser/support_tool/system_log_source_data_collector_adaptor.h
@@ -0,0 +1,79 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SUPPORT_TOOL_SYSTEM_LOG_SOURCE_DATA_COLLECTOR_ADAPTOR_H_
+#define CHROME_BROWSER_SUPPORT_TOOL_SYSTEM_LOG_SOURCE_DATA_COLLECTOR_ADAPTOR_H_
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
+#include "chrome/browser/support_tool/data_collector.h"
+#include "components/feedback/pii_types.h"
+#include "components/feedback/redaction_tool.h"
+#include "components/feedback/system_logs/system_logs_source.h"
+
+// SystemLogSourceDataCollectorAdaptor is an adaptor class from
+// system_logs::SystemLogsSource to DataCollector. It will take a
+// system_logs::SystemLogsSource instance and will use its functions in
+// DataCollector interface. SystemLogSourceDataCollectorAdaptor will use
+// feedback::RedactionTool for detection and removal of PII sensitive data.
+// Since this is an adaptor DataCollector, it will have many instances and the
+// caller of the class needs to give `description` as parameter to describe what
+// each SystemLogSourceDataCollector instance does in detail.
+class SystemLogSourceDataCollectorAdaptor : public DataCollector {
+ public:
+  SystemLogSourceDataCollectorAdaptor(
+      std::string description,
+      std::unique_ptr<system_logs::SystemLogsSource> log_source);
+
+  ~SystemLogSourceDataCollectorAdaptor() override;
+
+  // Overrides from DataCollector.
+  std::string GetName() const override;
+
+  std::string GetDescription() const override;
+
+  const PIIMap& GetDetectedPII() override;
+
+  void CollectDataAndDetectPII(
+      DataCollectorDoneCallback on_data_collected_callback,
+      scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
+      scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container)
+      override;
+
+  void ExportCollectedDataWithPII(
+      std::set<feedback::PIIType> pii_types_to_keep,
+      base::FilePath target_directory,
+      DataCollectorDoneCallback on_exported_callback) override;
+
+ private:
+  // Will be called when `log_source_` is done with its Fetch() function.
+  void OnDataFetched(
+      DataCollectorDoneCallback on_data_collected_callback,
+      scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
+      scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container,
+      std::unique_ptr<system_logs::SystemLogsResponse> system_logs_response);
+
+  void OnPIIDetected(DataCollectorDoneCallback on_data_collected_callback,
+                     PIIMap detected_pii);
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  // Description for the DataCollector.
+  std::string description_;
+  PIIMap pii_map_;
+  // The response that the SystemLogsSource returned. Contains a map
+  // std::strings that contains the collected logs.
+  std::unique_ptr<system_logs::SystemLogsResponse> system_logs_response_;
+  std::unique_ptr<system_logs::SystemLogsSource> log_source_;
+  base::WeakPtrFactory<SystemLogSourceDataCollectorAdaptor> weak_ptr_factory_{
+      this};
+};
+
+#endif  // CHROME_BROWSER_SUPPORT_TOOL_SYSTEM_LOG_SOURCE_DATA_COLLECTOR_ADAPTOR_H_
diff --git a/chrome/browser/support_tool/system_log_source_data_collector_adaptor_unittest.cc b/chrome/browser/support_tool/system_log_source_data_collector_adaptor_unittest.cc
new file mode 100644
index 0000000..f1f1b10
--- /dev/null
+++ b/chrome/browser/support_tool/system_log_source_data_collector_adaptor_unittest.cc
@@ -0,0 +1,107 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/support_tool/system_log_source_data_collector_adaptor.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "chrome/browser/support_tool/data_collector.h"
+#include "components/feedback/pii_types.h"
+#include "components/feedback/redaction_tool.h"
+#include "components/feedback/system_logs/system_logs_source.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+using ::testing::ContainerEq;
+
+// Test data that will be collected by TestLogSource.
+const char kTestData1[] =
+    "Collected data for testing:\nWill contain some PII sensitive info to test "
+    "functionality.\nSome IP addresss as PII here: 0.255.255.255, "
+    "::ffff:cb0c:10ea\n";
+const char kTestData2[] =
+    "More data for testing for this log source:\nFor example some URL address "
+    "that could be visited by user is "
+    "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js?bar=x and "
+    "this will be considered as PII.\n";
+
+// The PII sensitive data that the test data contains.
+const PIIMap kPIIInTestData = {
+    {feedback::PIIType::kIPAddress, {"0.255.255.255", "::ffff:cb0c:10ea"}},
+    {feedback::PIIType::kURL,
+     {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js?bar=x"}}};
+
+namespace {
+
+class TestLogSource : public system_logs::SystemLogsSource {
+ public:
+  TestLogSource() : SystemLogsSource("Test Log Source") {}
+
+  TestLogSource(const TestLogSource&) = delete;
+  TestLogSource& operator=(const TestLogSource&) = delete;
+
+  ~TestLogSource() override = default;
+
+  // SystemLogsSource override.
+  void Fetch(system_logs::SysLogsSourceCallback callback) override {
+    std::unique_ptr<system_logs::SystemLogsResponse> response =
+        std::make_unique<system_logs::SystemLogsResponse>();
+    // Add some test data to the response. We add two entries to make sure all
+    // entries are collected by the corresponding DataCollector instance.
+    response->emplace("test-log-source-1", kTestData1);
+    response->emplace("test-log-source-2", kTestData2);
+    std::move(callback).Run(std::move(response));
+  }
+};
+
+}  // namespace
+
+class SystemLogSourceDataCollectorAdaptorTest : public ::testing::Test {
+ public:
+  SystemLogSourceDataCollectorAdaptorTest() {
+    // Set up task runner and container for RedactionTool. We will use these
+    // when creating the SystemLogSourceDataCollector instance for testing.
+    task_runner_for_redaction_tool_ =
+        base::ThreadPool::CreateSequencedTaskRunner({});
+    redaction_tool_container_ =
+        base::MakeRefCounted<feedback::RedactionToolContainer>(
+            task_runner_for_redaction_tool_, nullptr);
+  }
+
+  SystemLogSourceDataCollectorAdaptorTest(
+      const SystemLogSourceDataCollectorAdaptorTest&) = delete;
+  SystemLogSourceDataCollectorAdaptorTest& operator=(
+      const SystemLogSourceDataCollectorAdaptorTest&) = delete;
+
+ protected:
+  base::test::TaskEnvironment task_environment_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool_;
+  scoped_refptr<feedback::RedactionToolContainer> redaction_tool_container_;
+};
+
+TEST_F(SystemLogSourceDataCollectorAdaptorTest, CollectDataAndDetectPII) {
+  // Initialize SystemLogSourceDataCollector for testing.
+  SystemLogSourceDataCollectorAdaptor data_collector(
+      "System Log Source Data Collector for testing",
+      std::make_unique<TestLogSource>());
+  base::test::TestFuture<absl::optional<SupportToolError>>
+      test_future_collect_data;
+  data_collector.CollectDataAndDetectPII(test_future_collect_data.GetCallback(),
+                                         task_runner_for_redaction_tool_,
+                                         redaction_tool_container_);
+  // Check if CollectDataAndDetectPII call returned an error.
+  absl::optional<SupportToolError> error = test_future_collect_data.Get();
+  EXPECT_EQ(error, absl::nullopt);
+  PIIMap detected_pii = data_collector.GetDetectedPII();
+  EXPECT_THAT(detected_pii, ContainerEq(kPIIInTestData));
+}
diff --git a/chrome/browser/sync/sync_service_factory_unittest.cc b/chrome/browser/sync/sync_service_factory_unittest.cc
index c466fd19..6750e7a 100644
--- a/chrome/browser/sync/sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -92,6 +92,7 @@
     // preprocessor conditions in ChromeSyncClient::CreateDataTypeControllers:
 
     // ChromeSyncClient types.
+    datatypes.push_back(syncer::READING_LIST);
     datatypes.push_back(syncer::SECURITY_EVENTS);
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
@@ -108,7 +109,6 @@
 
 #if !BUILDFLAG(IS_ANDROID)
     datatypes.push_back(syncer::THEMES);
-    datatypes.push_back(syncer::READING_LIST);
     datatypes.push_back(syncer::SEARCH_ENGINES);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
index eaa5220..e2eed8d 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -24,7 +24,6 @@
 import org.chromium.base.jank_tracker.JankTracker;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
 import org.chromium.chrome.browser.omnibox.R;
@@ -94,7 +93,6 @@
     private boolean mNativeInitialized;
     private AutocompleteController mAutocomplete;
     private long mUrlFocusTime;
-    private boolean mEnableAdaptiveSuggestionsCount;
     private boolean mShouldCacheSuggestions;
 
     @IntDef({SuggestionVisibilityState.DISALLOWED, SuggestionVisibilityState.PENDING_ALLOW,
@@ -277,11 +275,7 @@
      */
     void onNativeInitialized() {
         mNativeInitialized = true;
-
-        mEnableAdaptiveSuggestionsCount =
-                ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT);
         mDropdownViewInfoListBuilder.onNativeInitialized();
-
         runPendingAutocompleteRequests();
     }
 
@@ -892,8 +886,7 @@
 
     @Override
     public void onSuggestionDropdownScroll() {
-        if (mEnableAdaptiveSuggestionsCount
-                && mDropdownViewInfoListBuilder.hasFullyConcealedElements()) {
+        if (mDropdownViewInfoListBuilder.hasFullyConcealedElements()) {
             mDelegate.setKeyboardVisibility(false, false);
         }
     }
@@ -930,9 +923,7 @@
 
     @Override
     public void onSuggestionDropdownOverscrolledToTop() {
-        if (mEnableAdaptiveSuggestionsCount) {
-            mDelegate.setKeyboardVisibility(true, false);
-        }
+        mDelegate.setKeyboardVisibility(true, false);
     }
 
     /**
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilder.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilder.java
index a4755016..3e52765 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilder.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/DropdownItemViewInfoListBuilder.java
@@ -13,7 +13,6 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.answer.AnswerSuggestionProcessor;
 import org.chromium.chrome.browser.omnibox.suggestions.basic.BasicSuggestionProcessor;
@@ -60,7 +59,6 @@
     private @NonNull ExploreIconProvider mExploreIconProvider;
     @Px
     private int mDropdownHeight;
-    private boolean mEnableAdaptiveSuggestionsCount;
     private boolean mBuiltListHasFullyConcealedElements;
 
     DropdownItemViewInfoListBuilder(@NonNull Supplier<Tab> tabSupplier, BookmarkState bookmarkState,
@@ -211,9 +209,6 @@
 
     /** Signals that native initialization has completed. */
     void onNativeInitialized() {
-        mEnableAdaptiveSuggestionsCount =
-                ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT);
-
         mHeaderProcessor.onNativeInitialized();
         for (int index = 0; index < mPriorityOrderedSuggestionProcessors.size(); index++) {
             mPriorityOrderedSuggestionProcessors.get(index).onNativeInitialized();
@@ -239,7 +234,7 @@
         // When Adaptive Suggestions are set, perform partial grouping by search vs url.
         // Take action only if we have more suggestions to offer than just a default match and
         // one suggestion (otherwise no need to perform grouping).
-        if (suggestionsCount > 2 && mEnableAdaptiveSuggestionsCount) {
+        if (suggestionsCount > 2) {
             final int numVisibleSuggestions = getVisibleSuggestionsCount(autocompleteResult);
             // TODO(crbug.com/1073169): this should either infer the count from UI height or supply
             // the default value if height is not known. For the time being we group the entire list
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdown.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdown.java
index 8c05fd5..721aebe 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdown.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdown.java
@@ -29,7 +29,6 @@
 
 import org.chromium.base.TraceEvent;
 import org.chromium.base.task.PostTask;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.omnibox.R;
 import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
 import org.chromium.chrome.browser.util.KeyNavigationUtil;
@@ -486,7 +485,7 @@
                     currentInsets = mAnchorView.getRootWindowInsets();
                     result = !currentInsets.equals(mWindowInsets);
                     mWindowInsets = currentInsets;
-                } else if (isAdaptiveSuggestionsCountEnabled()) {
+                } else {
                     mEmbedder.getWindowDelegate().getWindowVisibleDisplayFrame(mTempRect);
                     result = !mTempRect.equals(mWindowRect);
                     mWindowRect.set(mTempRect);
@@ -517,11 +516,4 @@
                 mAnchorView.getWidth() - mAlignmentView.getWidth() - mTempPosition[0],
                 getPaddingBottom());
     }
-
-    /** Return whether Adaptive Suggestions Count feature is enabled. */
-    private boolean isAdaptiveSuggestionsCountEnabled() {
-        return ChromeFeatureList.isInitialized()
-                && ChromeFeatureList.isEnabled(
-                        ChromeFeatureList.OMNIBOX_ADAPTIVE_SUGGESTIONS_COUNT);
-    }
 }
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index ef989859..45d7eda 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -239,7 +239,12 @@
   }
 }
 
-void ChromeBrowserMainExtraPartsAsh::PostProfileInit() {
+void ChromeBrowserMainExtraPartsAsh::PostProfileInit(Profile* profile,
+                                                     bool is_initial_profile) {
+  // The setup below is intended to run for only the initial profile.
+  if (!is_initial_profile)
+    return;
+
   login_screen_client_ = std::make_unique<LoginScreenClientImpl>();
   // https://crbug.com/884127 ensuring that LoginScreenClientImpl is initialized
   // before using it InitializeDeviceDisablingManager.
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
index d39669a..0e5522f6 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
@@ -71,7 +71,7 @@
   // Overridden from ChromeBrowserMainExtraParts:
   void PreCreateMainMessageLoop() override;
   void PreProfileInit() override;
-  void PostProfileInit() override;
+  void PostProfileInit(Profile* profile, bool is_initial_profile) override;
   void PostBrowserStart() override;
   void PostMainMessageLoopRun() override;
 
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 1e15458..66fc82a 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -10,6 +10,7 @@
 #include "ash/constants/app_types.h"
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
+#include "ash/public/cpp/new_window_delegate.h"
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/command_line.h"
@@ -39,8 +40,6 @@
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
@@ -59,6 +58,8 @@
 #include "content/public/browser/media_session_service.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "extensions/browser/app_window/app_window.h"
+#include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/common/constants.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -110,13 +111,8 @@
 }
 
 void ChromeShellDelegate::OpenKeyboardShortcutHelpPage() const {
-  chrome::ScopedTabbedBrowserDisplayer scoped_tabbed_browser_displayer(
-      ProfileManager::GetActiveUserProfile());
-  NavigateParams params(scoped_tabbed_browser_displayer.browser(),
-                        GURL(kKeyboardShortcutHelpPageUrl),
-                        ui::PAGE_TRANSITION_AUTO_BOOKMARK);
-  params.disposition = WindowOpenDisposition::SINGLETON_TAB;
-  Navigate(&params);
+  ash::NewWindowDelegate::GetPrimary()->OpenUrl(
+      GURL(kKeyboardShortcutHelpPageUrl), /*from_user_interaction=*/true);
 }
 
 bool ChromeShellDelegate::CanGoBack(gfx::NativeWindow window) const {
@@ -315,3 +311,24 @@
 void ChromeShellDelegate::ResetDisableLoggingRedirectForTesting() {
   disable_logging_redirect_for_testing.reset();
 }
+
+const GURL& ChromeShellDelegate::GetLastCommittedURLForWindowIfAny(
+    aura::Window* window) {
+  // Get the web content if the window is a browser window.
+  content::WebContents* contents =
+      GetActiveWebContentsForNativeBrowserWindow(window);
+
+  if (!contents) {
+    // Get the web content if the window is an app window.
+    Profile* profile = ProfileManager::GetLastUsedProfile();
+    if (profile) {
+      const extensions::AppWindow* app_window =
+          extensions::AppWindowRegistry::Get(profile)
+              ->GetAppWindowForNativeWindow(window);
+      if (app_window)
+        contents = app_window->web_contents();
+    }
+  }
+
+  return contents ? contents->GetLastCommittedURL() : GURL::EmptyGURL();
+}
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 02b7e5dca..07155ed 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -9,6 +9,7 @@
 
 #include "ash/shell_delegate.h"
 #include "base/callback_forward.h"
+#include "url/gurl.h"
 
 class ChromeShellDelegate : public ash::ShellDelegate {
  public:
@@ -59,6 +60,7 @@
   void OpenFeedbackPageForPersistentDesksBar() override;
   static void SetDisableLoggingRedirectForTesting(bool value);
   static void ResetDisableLoggingRedirectForTesting();
+  const GURL& GetLastCommittedURLForWindowIfAny(aura::Window* window) override;
 };
 
 #endif  // CHROME_BROWSER_UI_ASH_CHROME_SHELL_DELEGATE_H_
diff --git a/chrome/browser/ui/views/profiles/profile_picker_signed_in_flow_controller.cc b/chrome/browser/ui/views/profiles/profile_picker_signed_in_flow_controller.cc
index c4506a2..81ba212 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_signed_in_flow_controller.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_signed_in_flow_controller.cc
@@ -377,9 +377,6 @@
   // Skip the FRE for this profile as it's replaced by profile creation flow.
   profile_->GetPrefs()->SetBoolean(prefs::kHasSeenWelcomePage, true);
 
-  // TODO(crbug.com/1126913): Change the callback of
-  // profiles::OpenBrowserWindowForProfile() to be a OnceCallback as it is only
-  // called once.
   profiles::OpenBrowserWindowForProfile(
       base::BindOnce(&ProfilePickerSignedInFlowController::OnBrowserOpened,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
@@ -389,7 +386,7 @@
                                      // extensions because we only open browser
                                      // window if the Profile is not locked.
                                      // Hence there is no extension blocked.
-      profile_, Profile::CREATE_STATUS_INITIALIZED);
+      profile_);
 }
 
 void ProfilePickerSignedInFlowController::FinishAndOpenBrowserForSAML() {
diff --git a/chrome/browser/ui/views/sync/inline_login_ui_browsertest.cc b/chrome/browser/ui/views/sync/inline_login_ui_browsertest.cc
index ebeeed6f..ac85919 100644
--- a/chrome/browser/ui/views/sync/inline_login_ui_browsertest.cc
+++ b/chrome/browser/ui/views/sync/inline_login_ui_browsertest.cc
@@ -192,7 +192,6 @@
     : InlineSigninHelper(handler,
                          url_loader_factory,
                          profile,
-                         Profile::CreateStatus::CREATE_STATUS_INITIALIZED,
                          current_url,
                          email,
                          gaia_id,
@@ -242,7 +241,6 @@
     : InlineSigninHelper(handler,
                          url_loader_factory,
                          profile,
-                         Profile::CreateStatus::CREATE_STATUS_INITIALIZED,
                          current_url,
                          email,
                          gaia_id,
diff --git a/chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc b/chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc
index 9523f4e..a6df295e 100644
--- a/chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc
+++ b/chrome/browser/ui/webui/access_code_cast/access_code_cast_ui.cc
@@ -140,6 +140,7 @@
   };
 
   source->AddLocalizedStrings(kStrings);
+  source->AddBoolean("qrScannerEnabled", false);
 
   content::BrowserContext* browser_context =
       web_ui->GetWebContents()->GetBrowserContext();
diff --git a/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc b/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc
index fc76f59..7125d3d 100644
--- a/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc
+++ b/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc
@@ -55,6 +55,21 @@
       base::BindOnce(&QuotaInternalsProxy::DidGetGlobalUsage,
                      weak_factory_.GetWeakPtr(), StorageType::kSyncable));
 
+  quota_manager_->GetStorageKeysForType(
+      StorageType::kTemporary,
+      base::BindOnce(&QuotaInternalsProxy::DidGetStorageKeys,
+                     weak_factory_.GetWeakPtr(), StorageType::kTemporary));
+
+  quota_manager_->GetStorageKeysForType(
+      StorageType::kPersistent,
+      base::BindOnce(&QuotaInternalsProxy::DidGetStorageKeys,
+                     weak_factory_.GetWeakPtr(), StorageType::kPersistent));
+
+  quota_manager_->GetStorageKeysForType(
+      StorageType::kSyncable,
+      base::BindOnce(&QuotaInternalsProxy::DidGetStorageKeys,
+                     weak_factory_.GetWeakPtr(), StorageType::kSyncable));
+
   quota_manager_->DumpQuotaTable(base::BindOnce(
       &QuotaInternalsProxy::DidDumpQuotaTable, weak_factory_.GetWeakPtr()));
 
@@ -123,7 +138,30 @@
   info.set_unlimited_usage(unlimited_usage);
 
   ReportGlobalInfo(info);
-  RequestPerOriginInfo(type);
+}
+
+void QuotaInternalsProxy::DidGetStorageKeys(
+    StorageType type,
+    const std::set<blink::StorageKey>& storage_keys) {
+  std::vector<PerOriginStorageInfo> origin_infos;
+  origin_infos.reserve(storage_keys.size());
+
+  std::set<std::string> hosts;
+  std::vector<PerHostStorageInfo> host_infos;
+
+  for (const blink::StorageKey& storage_key : storage_keys) {
+    PerOriginStorageInfo per_origin_info(storage_key.origin().GetURL(), type);
+    origin_infos.push_back(per_origin_info);
+
+    const std::string& host = storage_key.origin().host();
+    if (hosts.insert(host).second) {
+      PerHostStorageInfo per_host_info(host, type);
+      host_infos.push_back(per_host_info);
+      VisitHost(host, type);
+    }
+  }
+  ReportPerOriginInfo(origin_infos);
+  ReportPerHostInfo(host_infos);
 }
 
 void QuotaInternalsProxy::DidDumpQuotaTable(const QuotaTableEntries& entries) {
@@ -188,33 +226,6 @@
   ReportStatistics(stats_map);
 }
 
-void QuotaInternalsProxy::RequestPerOriginInfo(StorageType type) {
-  DCHECK(quota_manager_.get());
-
-  std::set<blink::StorageKey> storage_keys =
-      quota_manager_->GetCachedStorageKeys(type);
-
-  std::vector<PerOriginStorageInfo> origin_infos;
-  origin_infos.reserve(storage_keys.size());
-
-  std::set<std::string> hosts;
-  std::vector<PerHostStorageInfo> host_infos;
-
-  for (const blink::StorageKey& storage_key : storage_keys) {
-    PerOriginStorageInfo per_origin_info(storage_key.origin().GetURL(), type);
-    origin_infos.push_back(per_origin_info);
-
-    const std::string& host = storage_key.origin().host();
-    if (hosts.insert(host).second) {
-      PerHostStorageInfo per_host_info(host, type);
-      host_infos.push_back(per_host_info);
-      VisitHost(host, type);
-    }
-  }
-  ReportPerOriginInfo(origin_infos);
-  ReportPerHostInfo(host_infos);
-}
-
 void QuotaInternalsProxy::VisitHost(const std::string& host, StorageType type) {
   if (hosts_visited_.insert(std::make_pair(host, type)).second) {
     hosts_pending_.insert(std::make_pair(host, type));
diff --git a/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.h b/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.h
index 861d96ba3..81cf880 100644
--- a/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.h
+++ b/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.h
@@ -69,6 +69,8 @@
   void DidGetGlobalUsage(blink::mojom::StorageType type,
                          int64_t usage,
                          int64_t unlimited_usage);
+  void DidGetStorageKeys(blink::mojom::StorageType type,
+                         const std::set<blink::StorageKey>& storage_keys);
   void DidDumpQuotaTable(const QuotaTableEntries& entries);
   void DidDumpBucketTable(const BucketTableEntries& entries);
   void DidGetHostUsage(const std::string& host,
@@ -79,7 +81,6 @@
       const base::flat_map<std::string, std::string>& statistics);
 
   // Helper. Called on IO Thread.
-  void RequestPerOriginInfo(blink::mojom::StorageType type);
   void VisitHost(const std::string& host, blink::mojom::StorageType type);
   void GetHostUsage(const std::string& host, blink::mojom::StorageType type);
 
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 6ea0dc3..7a68181 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -307,7 +307,6 @@
     base::WeakPtr<InlineLoginHandlerImpl> handler,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     Profile* profile,
-    Profile::CreateStatus create_status,
     const GURL& current_url,
     const std::string& email,
     const std::string& gaia_id,
@@ -319,7 +318,6 @@
     : gaia_auth_fetcher_(this, gaia::GaiaSource::kChrome, url_loader_factory),
       handler_(handler),
       profile_(profile),
-      create_status_(create_status),
       current_url_(current_url),
       email_(email),
       gaia_id_(gaia_id),
@@ -349,7 +347,7 @@
         base::BindOnce(
             &InlineSigninHelper::OnClientOAuthSuccessAndBrowserOpened,
             base::Unretained(this), result),
-        true, false, true, profile_, create_status_);
+        true, false, true, profile_);
   } else {
     OnClientOAuthSuccessAndBrowserOpened(result, profile_);
   }
@@ -627,12 +625,13 @@
   Profile* profile = Profile::FromWebUI(web_ui());
   if (reason == HandlerSigninReason::kFetchLstOnly ||
       !profile->IsSystemProfile()) {
-    FinishCompleteLogin(FinishCompleteLoginParams(
-                            this, partition, current_url, base::FilePath(),
-                            confirm_untrusted_signin_, params.email,
-                            params.gaia_id, params.password, params.auth_code,
-                            params.choose_what_to_sync, false),
-                        profile, Profile::CREATE_STATUS_CREATED);
+    FinishCompleteLogin(
+        FinishCompleteLoginParams(this, partition, current_url,
+                                  base::FilePath(), confirm_untrusted_signin_,
+                                  params.email, params.gaia_id, params.password,
+                                  params.auth_code, params.choose_what_to_sync,
+                                  /*is_force_sign_in_with_usermanager=*/false),
+        profile);
     return;
   }
 
@@ -653,11 +652,11 @@
   FinishCompleteLoginParams finish_login_params(
       this, partition, current_url, path, confirm_untrusted_signin_,
       params.email, params.gaia_id, params.password, params.auth_code,
-      params.choose_what_to_sync, true);
-  ProfileManager::CreateCallback callback = base::BindRepeating(
+      params.choose_what_to_sync, /*is_force_sign_in_with_usermanager=*/true);
+  base::OnceCallback<void(Profile*)> callback = base::BindOnce(
       &InlineLoginHandlerImpl::FinishCompleteLogin, finish_login_params);
   // Browser window will be opened after ClientOAuthSuccess.
-  profiles::LoadProfileAsync(path, callback);
+  profiles::LoadProfileAsync(path, std::move(callback));
 }
 
 InlineLoginHandlerImpl::FinishCompleteLoginParams::FinishCompleteLoginParams(
@@ -693,8 +692,7 @@
 // static
 void InlineLoginHandlerImpl::FinishCompleteLogin(
     const FinishCompleteLoginParams& params,
-    Profile* profile,
-    Profile::CreateStatus status) {
+    Profile* profile) {
   DCHECK(params.handler);
   HandlerSigninReason reason = GetHandlerSigninReason(params.url);
 
@@ -777,7 +775,7 @@
   // InlineSigninHelper will delete itself.
   new InlineSigninHelper(
       params.handler->GetWeakPtr(),
-      params.partition->GetURLLoaderFactoryForBrowserProcess(), profile, status,
+      params.partition->GetURLLoaderFactoryForBrowserProcess(), profile,
       params.url, params.email, params.gaia_id, params.password,
       params.auth_code, signin_scoped_device_id,
       params.confirm_untrusted_signin,
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
index 0447df3..6169894 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
@@ -114,8 +114,7 @@
   };
 
   static void FinishCompleteLogin(const FinishCompleteLoginParams& params,
-                                  Profile* profile,
-                                  Profile::CreateStatus status);
+                                  Profile* profile);
 
   // True if the user has navigated to untrusted domains during the signin
   // process.
@@ -135,7 +134,6 @@
       base::WeakPtr<InlineLoginHandlerImpl> handler,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       Profile* profile,
-      Profile::CreateStatus create_status,
       const GURL& current_url,
       const std::string& email,
       const std::string& gaia_id,
@@ -174,14 +172,13 @@
   GaiaAuthFetcher gaia_auth_fetcher_;
   base::WeakPtr<InlineLoginHandlerImpl> handler_;
   raw_ptr<Profile> profile_;
-  Profile::CreateStatus create_status_;
-  GURL current_url_;
-  std::string email_;
-  std::string gaia_id_;
-  std::string password_;
-  std::string auth_code_;
-  bool confirm_untrusted_signin_;
-  bool is_force_sign_in_with_usermanager_;
+  const GURL current_url_;
+  const std::string email_;
+  const std::string gaia_id_;
+  const std::string password_;
+  const std::string auth_code_;
+  const bool confirm_untrusted_signin_;
+  const bool is_force_sign_in_with_usermanager_;
 };
 
 #endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_INLINE_LOGIN_HANDLER_IMPL_H_
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
index 8651d82..57b272d 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -773,7 +773,7 @@
       false,  // There is no need to unblock all extensions because we only open
               // browser window if the Profile is not locked. Hence there is no
               // extension blocked.
-      profile, Profile::CREATE_STATUS_INITIALIZED);
+      profile);
 }
 
 void ProfilePickerHandler::HandleRecordSignInPromoImpression(
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java
index 54cc296..dfde561 100644
--- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java
+++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java
@@ -23,8 +23,6 @@
     /**
      * Sends data back to the server when content is clicked.
      */
-    default void processThereAndBackAgainData(byte[] data) {}
-
     default void processThereAndBackAgainData(byte[] data, LoggingParameters loggingParameters) {}
 
     /**
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ProcessScopeDependencyProvider.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ProcessScopeDependencyProvider.java
index 63bf2dbe..51c4c8b9 100644
--- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ProcessScopeDependencyProvider.java
+++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ProcessScopeDependencyProvider.java
@@ -133,8 +133,6 @@
      * message.
      */
     default void processViewAction(byte[] data, LoggingParameters loggingParameters) {}
-    @Deprecated
-    default void processViewAction(byte[] data) {}
 
     /**
      * Reports whether the visibility log upload was successful.
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/SurfaceScopeDependencyProvider.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/SurfaceScopeDependencyProvider.java
index 57116018..ada9c22 100644
--- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/SurfaceScopeDependencyProvider.java
+++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/SurfaceScopeDependencyProvider.java
@@ -148,6 +148,7 @@
     default void removeHeaderOffsetObserver(SurfaceHeaderOffsetObserver observer) {}
 
     /** Returns whether or not activity logging should be enabled. */
+    @Deprecated
     default boolean isActivityLoggingEnabled() {
         return false;
     }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index a12c3e42..fafbe53 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1641988738-3f3ebd615a29f94ce1d06e8bb15454c84b0f5d12.profdata
+chrome-linux-main-1642010411-12c22ef7f8f5650de4b50b11575ceca3dfdb10c4.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 0f6e6fe..506bc1ba 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1641988738-f17e69946ec828cffd08af1090867007ba68fc1e.profdata
+chrome-win32-main-1641999328-dbfb688ed5fc5376e24a90f16652a36471418d74.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 6c7efd96..ee9da3a 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1641988738-06d0b3dddf49a26a7586f67a63839d852efdaf8c.profdata
+chrome-win64-main-1641999328-dc06bafe3cd3be0e04b3112c1d4b5a52ca61f0a9.profdata
diff --git a/chrome/credential_provider/gaiacp/win_http_url_fetcher.cc b/chrome/credential_provider/gaiacp/win_http_url_fetcher.cc
index 60806a74..235b35af 100644
--- a/chrome/credential_provider/gaiacp/win_http_url_fetcher.cc
+++ b/chrome/credential_provider/gaiacp/win_http_url_fetcher.cc
@@ -10,16 +10,18 @@
 #include <atlconv.h>
 #include <process.h>
 
-#include <set>
 #include <string>
 
 #include "base/base64.h"
+#include "base/containers/contains.h"
 #include "base/containers/span.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
 #include "base/time/time.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 
@@ -32,7 +34,7 @@
 const char kErrorKeyInRequestResult[] = "error";
 
 // The HTTP response codes for which the request is re-tried on failure.
-const std::set<int> kRetryableHttpErrorCodes = {
+constexpr int kRetryableHttpErrorCodes[] = {
     503,  // Service Unavailable
     504   // Gateway Timeout
 };
@@ -76,21 +78,20 @@
     // or the thread finishes.
     unsigned wait_thread_id;
     uintptr_t wait_thread = ::_beginthreadex(
-        nullptr, 0, &HttpServiceRequest::FetchResultFromHttpService,
-        reinterpret_cast<void*>(this), 0, &wait_thread_id);
+        nullptr, 0, &HttpServiceRequest::FetchResultFromHttpService, this, 0,
+        &wait_thread_id);
 
     HRESULT hr = S_OK;
-    if (wait_thread == 0) {
+    if (wait_thread == 0)
       return result;
-    } else {
-      // Hold the handle in the scoped handle so that it can be immediately
-      // closed when the wait is complete allowing the thread to finish
-      // completely if needed.
-      base::win::ScopedHandle thread_handle(
-          reinterpret_cast<HANDLE>(wait_thread));
-      hr = ::WaitForSingleObject(thread_handle.Get(),
-                                 request_timeout.InMilliseconds());
-    }
+
+    // Hold the handle in the scoped handle so that it can be immediately
+    // closed when the wait is complete allowing the thread to finish
+    // completely if needed.
+    base::win::ScopedHandle thread_handle(
+        reinterpret_cast<HANDLE>(wait_thread));
+    hr = ::WaitForSingleObject(thread_handle.Get(),
+                               request_timeout.InMilliseconds());
 
     // The race condition starts here. It is possible that between the expiry of
     // the timeout in the call for WaitForSingleObject and the call to
@@ -164,9 +165,8 @@
   // as finished processing when it is done.
   static unsigned __stdcall FetchResultFromHttpService(void* param) {
     DCHECK(param);
-    HttpServiceRequest* requester =
-        reinterpret_cast<HttpServiceRequest*>(param);
 
+    auto* requester = reinterpret_cast<HttpServiceRequest*>(param);
     HRESULT hr = requester->fetcher_->Fetch(&requester->response_);
     if (FAILED(hr))
       LOGFN(ERROR) << "fetcher.Fetch hr=" << credential_provider::putHR(hr);
@@ -218,7 +218,7 @@
     url_fetcher->SetHttpRequestTimeout(request_timeout.InMilliseconds());
   }
 
-  return (new HttpServiceRequest(std::move(url_fetcher)));
+  return new HttpServiceRequest(std::move(url_fetcher));
 }
 
 }  // namespace
@@ -236,7 +236,7 @@
 std::unique_ptr<WinHttpUrlFetcher> WinHttpUrlFetcher::Create(const GURL& url) {
   return !GetCreatorFunctionStorage()->is_null()
              ? GetCreatorFunctionStorage()->Run(url)
-             : std::unique_ptr<WinHttpUrlFetcher>(new WinHttpUrlFetcher(url));
+             : base::WrapUnique(new WinHttpUrlFetcher(url));
 }
 
 // static
@@ -258,7 +258,7 @@
   session_.Set(session);
 }
 
-WinHttpUrlFetcher::WinHttpUrlFetcher() {}
+WinHttpUrlFetcher::WinHttpUrlFetcher() = default;
 
 WinHttpUrlFetcher::~WinHttpUrlFetcher() {
   // Closing the session handle closes all derived handles too.
@@ -391,7 +391,7 @@
   // buffer than 256k.
   constexpr size_t kMaxResponseSize = 256 * 1024 * 1024;
   // Read the response.
-  std::unique_ptr<char> buffer(new char[length]);
+  auto buffer = std::make_unique<char[]>(length);
   DWORD actual = 0;
   do {
     if (!::WinHttpReadData(request_.Get(), buffer.get(), length, &actual)) {
@@ -426,7 +426,6 @@
     unsigned int request_retries,
     absl::optional<base::Value>* request_result) {
   DCHECK(request_result);
-  HRESULT hr = S_OK;
 
   std::string request_body;
   if (request_dict.is_dict()) {
@@ -439,40 +438,32 @@
   for (unsigned int try_count = 0; try_count <= request_retries; ++try_count) {
     HttpServiceRequest* request = HttpServiceRequest::Create(
         request_url, access_token, headers, request_body, request_timeout);
-
     if (!request)
       return E_FAIL;
 
     auto extracted_param =
         request->WaitForResponseFromHttpService(request_timeout);
-
-    if (!extracted_param) {
-      hr = E_FAIL;
+    if (!extracted_param)
       continue;
-    }
+
     *request_result = std::move(extracted_param);
-
-    base::Value* error_detail =
+    const base::Value* error_detail =
         (*request_result)->FindDictKey(kErrorKeyInRequestResult);
-    if (error_detail) {
-      hr = E_FAIL;
-      LOGFN(ERROR) << "error: " << *error_detail;
+    if (!error_detail)
+      return S_OK;
 
-      // If error code is known, retry only on retryable server errors.
-      absl::optional<int> error_code =
-          error_detail->FindIntKey(kHttpErrorCodeKeyNameInResponse);
-      if (error_code.has_value() &&
-          kRetryableHttpErrorCodes.find(error_code.value()) ==
-              kRetryableHttpErrorCodes.end())
-        break;
+    LOGFN(ERROR) << "error: " << *error_detail;
 
-      continue;
+    // If error code is known, retry only on retryable server errors.
+    absl::optional<int> error_code =
+        error_detail->FindIntKey(kHttpErrorCodeKeyNameInResponse);
+    if (error_code.has_value() &&
+        !base::Contains(kRetryableHttpErrorCodes, error_code.value())) {
+      return E_FAIL;
     }
-
-    hr = S_OK;
-    break;
   }
 
-  return hr;
+  return E_FAIL;
 }
+
 }  // namespace credential_provider
diff --git a/chrome/services/sharing/nearby/platform/wifi_lan_medium.cc b/chrome/services/sharing/nearby/platform/wifi_lan_medium.cc
index 8e2219b..daddc66 100644
--- a/chrome/services/sharing/nearby/platform/wifi_lan_medium.cc
+++ b/chrome/services/sharing/nearby/platform/wifi_lan_medium.cc
@@ -63,13 +63,16 @@
 }  // namespace
 
 WifiLanMedium::WifiLanMedium(
-    const mojo::SharedRemote<sharing::mojom::TcpSocketFactory>& socket_factory)
+    const mojo::SharedRemote<sharing::mojom::TcpSocketFactory>& socket_factory,
+    const mojo::SharedRemote<sharing::mojom::FirewallHoleFactory>&
+        firewall_hole_factory)
     : task_runner_(
           base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})),
-      socket_factory_(socket_factory) {
-  // NOTE: We do not set the disconnect handler for |socket_factory_| here. It
-  // is a fundamental dependency of the Nearby Connections process, which will
-  // crash if any dependency disconnects.
+      socket_factory_(socket_factory),
+      firewall_hole_factory_(firewall_hole_factory) {
+  // NOTE: We do not set the disconnect handler for |socket_factory_| or
+  // |firewall_hole_factory_| here. They are fundamental dependencies of the
+  // Nearby Connections process, which will crash if any dependency disconnects.
 }
 
 WifiLanMedium::~WifiLanMedium() {
@@ -284,7 +287,6 @@
     int32_t result,
     const absl::optional<net::IPEndPoint>& local_addr) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
   // TODO(https://crbug.com/1261238): Log metric.
   if (result != net::OK) {
     LOG(WARNING) << "WifiLanMedium::" << __func__
@@ -312,9 +314,11 @@
     return;
   }
 
-  // TODO(https://crbug.com/1261238): Open firewall hole.
-  OnFirewallHoleCreated(server_socket_parameters, listen_waitable_event,
-                        std::move(tcp_server_socket), *local_addr);
+  firewall_hole_factory_->OpenFirewallHole(
+      port, base::BindOnce(&WifiLanMedium::OnFirewallHoleCreated,
+                           base::Unretained(this), server_socket_parameters,
+                           listen_waitable_event, std::move(tcp_server_socket),
+                           *local_addr));
 }
 
 void WifiLanMedium::OnFirewallHoleCreated(
@@ -322,13 +326,21 @@
         server_socket_parameters,
     base::WaitableEvent* listen_waitable_event,
     mojo::PendingRemote<network::mojom::TCPServerSocket> tcp_server_socket,
-    const net::IPEndPoint& local_addr) {
+    const net::IPEndPoint& local_addr,
+    mojo::PendingRemote<sharing::mojom::FirewallHole> firewall_hole) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
-  // TODO(https://crbug.com/1261238): Process firewall hole, log metric, and add
-  // firewall hole to server socket parameters.
-
-  *server_socket_parameters = {local_addr, std::move(tcp_server_socket)};
+  // TODO(https://crbug.com/1261238): Log metric.
+  if (firewall_hole) {
+    VLOG(1) << "WifiLanMedium::" << __func__
+            << ": Created firewall hole. local_addr=" << local_addr.ToString();
+    *server_socket_parameters = {local_addr, std::move(tcp_server_socket),
+                                 std::move(firewall_hole)};
+  } else {
+    LOG(WARNING) << "WifiLanMedium::" << __func__
+                 << ": Failed to create firewall hole. local_addr="
+                 << local_addr.ToString();
+  }
 
   FinishListenAttempt(listen_waitable_event);
 }
@@ -392,10 +404,10 @@
 
   // Note that resetting the Remote will cancel any pending callbacks, including
   // those already in the task queue.
-  // TODO(https://crbug.com/1261238): Reset firewall hole factory.
   VLOG(1) << "WifiLanMedium::" << __func__
-          << ": Closing TcpSocketFactory Remote.";
+          << ": Closing TcpSocketFactory and FirewallHoleFactory Remotes.";
   socket_factory_.reset();
+  firewall_hole_factory_.reset();
 
   // Cancel all pending connect/listen calls. This is thread safe because all
   // changes to the pending-event sets are sequenced. Make a copy of the events
diff --git a/chrome/services/sharing/nearby/platform/wifi_lan_medium.h b/chrome/services/sharing/nearby/platform/wifi_lan_medium.h
index 8f329718..615b581 100644
--- a/chrome/services/sharing/nearby/platform/wifi_lan_medium.h
+++ b/chrome/services/sharing/nearby/platform/wifi_lan_medium.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "ash/services/nearby/public/mojom/firewall_hole.mojom.h"
 #include "ash/services/nearby/public/mojom/tcp_socket_factory.mojom.h"
 #include "base/containers/flat_set.h"
 #include "base/memory/scoped_refptr.h"
@@ -48,9 +49,10 @@
 // connection and listening attempts return before destruction.
 class WifiLanMedium : public api::WifiLanMedium {
  public:
-  explicit WifiLanMedium(
-      const mojo::SharedRemote<sharing::mojom::TcpSocketFactory>&
-          socket_factory);
+  WifiLanMedium(const mojo::SharedRemote<sharing::mojom::TcpSocketFactory>&
+                    socket_factory,
+                const mojo::SharedRemote<sharing::mojom::FirewallHoleFactory>&
+                    firewall_hole_factory);
   WifiLanMedium(const WifiLanMedium&) = delete;
   WifiLanMedium& operator=(const WifiLanMedium&) = delete;
   ~WifiLanMedium() override;
@@ -108,13 +110,13 @@
       const ash::nearby::TcpServerSocketPort& port,
       int32_t result,
       const absl::optional<net::IPEndPoint>& local_addr);
-  // TODO(https://crbug.com/1261238): Add firewall hole PendingRemote argument.
   void OnFirewallHoleCreated(
       absl::optional<WifiLanServerSocket::ServerSocketParameters>*
           server_socket_parameters,
       base::WaitableEvent* listen_waitable_event,
       mojo::PendingRemote<network::mojom::TCPServerSocket> tcp_server_socket,
-      const net::IPEndPoint& local_addr);
+      const net::IPEndPoint& local_addr,
+      mojo::PendingRemote<sharing::mojom::FirewallHole> firewall_hole);
   /*==========================================================================*/
 
   /*==========================================================================*/
@@ -138,9 +140,10 @@
   // attempts with null results.
   void Shutdown(base::WaitableEvent* shutdown_waitable_event);
 
-  // TODO(https://crbug.com/1261238): Add firewall hole factory.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   mojo::SharedRemote<sharing::mojom::TcpSocketFactory> socket_factory_;
+  mojo::SharedRemote<sharing::mojom::FirewallHoleFactory>
+      firewall_hole_factory_;
 
   // Track all pending connect/listen tasks in case Close() is called while
   // waiting.
diff --git a/chrome/services/sharing/nearby/platform/wifi_lan_medium_unittest.cc b/chrome/services/sharing/nearby/platform/wifi_lan_medium_unittest.cc
index 03de1a7f..beae8dde 100644
--- a/chrome/services/sharing/nearby/platform/wifi_lan_medium_unittest.cc
+++ b/chrome/services/sharing/nearby/platform/wifi_lan_medium_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/services/sharing/nearby/platform/wifi_lan_medium.h"
 
 #include "ash/services/nearby/public/cpp/tcp_server_socket_port.h"
+#include "ash/services/nearby/public/mojom/firewall_hole.mojom.h"
 #include "base/task/thread_pool.h"
 #include "base/test/task_environment.h"
 #include "chrome/services/sharing/nearby/platform/fake_tcp_socket_factory.h"
@@ -30,6 +31,35 @@
 const char kRemoteIpString[] = "\xC0\xA8\x56\x3E";
 const int kRemotePort = ash::nearby::TcpServerSocketPort::kMax;
 
+class FakeFirewallHole : public sharing::mojom::FirewallHole {
+ public:
+  FakeFirewallHole() = default;
+  ~FakeFirewallHole() override = default;
+};
+
+class FakeFirewallHoleFactory : public sharing::mojom::FirewallHoleFactory {
+ public:
+  FakeFirewallHoleFactory() = default;
+  ~FakeFirewallHoleFactory() override = default;
+
+  // Immediately invokes |callback| with a fake firewall hole if
+  // |should_succeed_| is true and NullRemote if false.
+  void OpenFirewallHole(const ash::nearby::TcpServerSocketPort& port,
+                        OpenFirewallHoleCallback callback) override {
+    if (should_succeed_) {
+      mojo::PendingRemote<sharing::mojom::FirewallHole> firewall_hole;
+      mojo::MakeSelfOwnedReceiver(
+          std::make_unique<FakeFirewallHole>(),
+          firewall_hole.InitWithNewPipeAndPassReceiver());
+      std::move(callback).Run(std::move(firewall_hole));
+    } else {
+      std::move(callback).Run(/*firewall_hole=*/mojo::NullRemote());
+    }
+  }
+
+  bool should_succeed_ = true;
+};
+
 }  // namespace
 
 class WifiLanMediumTest : public ::testing::Test {
@@ -47,8 +77,15 @@
         std::move(fake_socket_factory),
         socket_factory_shared_remote_.BindNewPipeAndPassReceiver());
 
-    wifi_lan_medium_ =
-        std::make_unique<WifiLanMedium>(socket_factory_shared_remote_);
+    auto fake_firewall_hole_factory =
+        std::make_unique<FakeFirewallHoleFactory>();
+    fake_firewall_hole_factory_ = fake_firewall_hole_factory.get();
+    mojo::MakeSelfOwnedReceiver(
+        std::move(fake_firewall_hole_factory),
+        firewall_hole_factory_shared_remote_.BindNewPipeAndPassReceiver());
+
+    wifi_lan_medium_ = std::make_unique<WifiLanMedium>(
+        socket_factory_shared_remote_, firewall_hole_factory_shared_remote_);
   }
 
   void TearDown() override { wifi_lan_medium_.reset(); }
@@ -141,8 +178,11 @@
   base::OnceClosure on_connect_calls_finished_;
   base::OnceClosure on_listen_calls_finished_;
   FakeTcpSocketFactory* fake_socket_factory_;
+  FakeFirewallHoleFactory* fake_firewall_hole_factory_;
   mojo::SharedRemote<sharing::mojom::TcpSocketFactory>
       socket_factory_shared_remote_;
+  mojo::SharedRemote<sharing::mojom::FirewallHoleFactory>
+      firewall_hole_factory_shared_remote_;
   std::unique_ptr<WifiLanMedium> wifi_lan_medium_;
 };
 
@@ -270,6 +310,20 @@
   run_loop.Run();
 }
 
+TEST_F(WifiLanMediumTest, Listen_Failure_CreateFirewallHole) {
+  // Fail to create the firewall hole.
+  fake_firewall_hole_factory_->should_succeed_ = false;
+
+  base::RunLoop run_loop;
+  CallListenForServiceFromThreads(
+      /*num_threads=*/1u,
+      /*expected_num_calls_sent_to_socket_factory=*/1u,
+      /*expected_success=*/false,
+      /*on_listen_calls_finished=*/run_loop.QuitClosure());
+  fake_socket_factory_->FinishNextCreateServerSocket(net::OK);
+  run_loop.Run();
+}
+
 TEST_F(WifiLanMediumTest, Listen_Failure_InvalidPort) {
   base::ScopedAllowBaseSyncPrimitivesForTesting allow;
   EXPECT_FALSE(wifi_lan_medium_->ListenForService(/*port=*/-1));
diff --git a/chrome/services/sharing/nearby/platform/wifi_lan_server_socket.cc b/chrome/services/sharing/nearby/platform/wifi_lan_server_socket.cc
index 2b85d73..a077db6 100644
--- a/chrome/services/sharing/nearby/platform/wifi_lan_server_socket.cc
+++ b/chrome/services/sharing/nearby/platform/wifi_lan_server_socket.cc
@@ -17,9 +17,11 @@
 
 WifiLanServerSocket::ServerSocketParameters::ServerSocketParameters(
     const net::IPEndPoint& local_end_point,
-    mojo::PendingRemote<network::mojom::TCPServerSocket> tcp_server_socket)
+    mojo::PendingRemote<network::mojom::TCPServerSocket> tcp_server_socket,
+    mojo::PendingRemote<sharing::mojom::FirewallHole> firewall_hole)
     : local_end_point(local_end_point),
-      tcp_server_socket(std::move(tcp_server_socket)) {}
+      tcp_server_socket(std::move(tcp_server_socket)),
+      firewall_hole(std::move(firewall_hole)) {}
 
 WifiLanServerSocket::ServerSocketParameters::~ServerSocketParameters() =
     default;
@@ -37,11 +39,17 @@
       task_runner_(
           base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})),
       tcp_server_socket_(std::move(server_socket_parameters.tcp_server_socket),
-                         task_runner_) {
+                         task_runner_),
+      firewall_hole_(std::move(server_socket_parameters.firewall_hole),
+                     task_runner_) {
   tcp_server_socket_.set_disconnect_handler(
       base::BindOnce(&WifiLanServerSocket::OnTcpServerSocketDisconnected,
                      base::Unretained(this)),
       task_runner_);
+  firewall_hole_.set_disconnect_handler(
+      base::BindOnce(&WifiLanServerSocket::OnFirewallHoleDisconnected,
+                     base::Unretained(this)),
+      task_runner_);
 }
 
 WifiLanServerSocket::~WifiLanServerSocket() {
@@ -99,8 +107,6 @@
     return;
   }
 
-  // TODO(https://crbug.com/1261238): Open firewall hole.
-
   VLOG(1) << "WifiLanServerSocket::" << __func__
           << ": Start accepting incoming connections.";
   tcp_server_socket_->Accept(
@@ -164,12 +170,14 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   if (!IsClosed()) {
-    // Note that resetting the Remote will cancel any pending TCPServerSocket
-    // callbacks, including those already in the task queue.
+    // Note that resetting the Remote will cancel any pending callbacks,
+    // including those already in the task queue.
     VLOG(1) << "WifiLanServerSocket::" << __func__
-            << ": Closing TCP server socket.";
+            << ": Closing TCP server socket and firewall hole.";
     DCHECK(tcp_server_socket_);
     tcp_server_socket_.reset();
+    DCHECK(firewall_hole_);
+    firewall_hole_.reset();
 
     // Cancel all pending Accept() calls. This is thread safe because all
     // changes to |pending_accept_waitable_events_| are sequenced. Make a copy
@@ -195,6 +203,7 @@
 
 bool WifiLanServerSocket::IsClosed() const {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK_EQ(tcp_server_socket_.is_bound(), firewall_hole_.is_bound());
   return !tcp_server_socket_.is_bound();
 }
 
@@ -217,6 +226,14 @@
   Close();
 }
 
+void WifiLanServerSocket::OnFirewallHoleDisconnected() {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  LOG(WARNING) << "WifiLanServerSocket::" << __func__
+               << ": Firewall hole unexpectedly disconnected. Closing "
+               << "WifiLanServerSocket.";
+  Close();
+}
+
 }  // namespace chrome
 }  // namespace nearby
 }  // namespace location
diff --git a/chrome/services/sharing/nearby/platform/wifi_lan_server_socket.h b/chrome/services/sharing/nearby/platform/wifi_lan_server_socket.h
index e211c15d..a86820c 100644
--- a/chrome/services/sharing/nearby/platform/wifi_lan_server_socket.h
+++ b/chrome/services/sharing/nearby/platform/wifi_lan_server_socket.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "ash/services/nearby/public/mojom/firewall_hole.mojom.h"
 #include "base/containers/flat_set.h"
 #include "base/memory/scoped_refptr.h"
 #include "chrome/services/sharing/nearby/platform/wifi_lan_socket.h"
@@ -29,30 +30,30 @@
 namespace chrome {
 
 // An implementation of Nearby Connections's abstract class
-// api::WifiLanServerSocket. This implementation wraps a TCPServerSocket which
-// lives until Close() is called or the WifiLanServerSocket instance is
-// destroyed.
+// api::WifiLanServerSocket. This implementation wraps a TCPServerSocket and
+// FirewallHole which live until Close() is called or the WifiLanServerSocket
+// instance is destroyed.
 //
 // The methods Accept() and Close() are thread safe as is the destructor, which
 // closes the socket if not closed already. Accept() and Close() are blocking.
 // All pending Accept() calls are guaranteed to return after Close() is called
 // or before destruction. All pending Close() calls are guaranteed to return
 // before destruction.
-//
-// TODO(https://crbug.com/1261238): Comment on firewall hole strategy.
 class WifiLanServerSocket : public api::WifiLanServerSocket {
  public:
   // Parameters needed to construct a WifiLanServerSocket.
   struct ServerSocketParameters {
     ServerSocketParameters(
         const net::IPEndPoint& local_end_point,
-        mojo::PendingRemote<network::mojom::TCPServerSocket> tcp_server_socket);
+        mojo::PendingRemote<network::mojom::TCPServerSocket> tcp_server_socket,
+        mojo::PendingRemote<sharing::mojom::FirewallHole> firewall_hole);
     ~ServerSocketParameters();
     ServerSocketParameters(ServerSocketParameters&&);
     ServerSocketParameters& operator=(ServerSocketParameters&&);
 
     net::IPEndPoint local_end_point;
     mojo::PendingRemote<network::mojom::TCPServerSocket> tcp_server_socket;
+    mojo::PendingRemote<sharing::mojom::FirewallHole> firewall_hole;
   };
 
   explicit WifiLanServerSocket(ServerSocketParameters server_socket_parameters);
@@ -97,12 +98,19 @@
   // Calls to this method are sequenced on |task_runner_| and thus thread safe.
   void FinishAcceptAttempt(base::WaitableEvent* event);
 
-  // Close if the TCP server socket disconnects.
+  // Close if the TCP server socket or firewall hole disconnect.
   void OnTcpServerSocketDisconnected();
+  void OnFirewallHoleDisconnected();
 
   const net::IPEndPoint local_end_point_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  // Uniquely owned by the WifiLanServerSocket instance. The underlying
+  // TCPServerSocket/FirewallHole implementation is destroyed when the
+  // corresponding remote endpoint, |tcp_server_socket_|/|firewall_hole_|, is
+  // destroyed.
   mojo::SharedRemote<network::mojom::TCPServerSocket> tcp_server_socket_;
+  mojo::SharedRemote<sharing::mojom::FirewallHole> firewall_hole_;
 
   // Track all pending accept tasks in case Close() is called while waiting.
   base::flat_set<base::WaitableEvent*> pending_accept_waitable_events_;
diff --git a/chrome/services/sharing/nearby/platform/wifi_lan_server_socket_unittest.cc b/chrome/services/sharing/nearby/platform/wifi_lan_server_socket_unittest.cc
index 4956ce7..ef339c7 100644
--- a/chrome/services/sharing/nearby/platform/wifi_lan_server_socket_unittest.cc
+++ b/chrome/services/sharing/nearby/platform/wifi_lan_server_socket_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/services/nearby/public/mojom/firewall_hole.mojom.h"
 #include "base/run_loop.h"
 #include "base/task/thread_pool.h"
 #include "base/test/bind.h"
@@ -34,6 +35,12 @@
 
 const net::IPEndPoint kRemoteAddress(net::IPAddress(192, 168, 86, 62), 33333);
 
+class FakeFirewallHole : public sharing::mojom::FirewallHole {
+ public:
+  FakeFirewallHole() = default;
+  ~FakeFirewallHole() override = default;
+};
+
 }  // namespace
 
 class WifiLanServerSocketTest : public testing::Test {
@@ -51,9 +58,15 @@
         std::move(fake_tcp_server_socket),
         tcp_server_socket.InitWithNewPipeAndPassReceiver());
 
+    mojo::PendingRemote<sharing::mojom::FirewallHole> firewall_hole;
+    firewall_hole_self_owned_receiver_ref_ = mojo::MakeSelfOwnedReceiver(
+        std::make_unique<FakeFirewallHole>(),
+        firewall_hole.InitWithNewPipeAndPassReceiver());
+
     wifi_lan_server_socket_ = std::make_unique<WifiLanServerSocket>(
         WifiLanServerSocket::ServerSocketParameters(
-            kLocalAddress, std::move(tcp_server_socket)));
+            kLocalAddress, std::move(tcp_server_socket),
+            std::move(firewall_hole)));
   }
 
   void TearDown() override { wifi_lan_server_socket_.reset(); }
@@ -105,6 +118,8 @@
   FakeTcpServerSocket* fake_tcp_server_socket_;
   mojo::SelfOwnedReceiverRef<network::mojom::TCPServerSocket>
       tcp_server_socket_self_owned_receiver_ref_;
+  mojo::SelfOwnedReceiverRef<sharing::mojom::FirewallHole>
+      firewall_hole_self_owned_receiver_ref_;
   std::unique_ptr<WifiLanServerSocket> wifi_lan_server_socket_;
 };
 
@@ -235,7 +250,8 @@
   run_loop.Run();
 }
 
-TEST_F(WifiLanServerSocketTest, Disconnect_WhileWaitingForAccept) {
+TEST_F(WifiLanServerSocketTest,
+       Disconnect_WhileWaitingForAccept_TcpServerSocket) {
   const size_t kNumThreads = 3;
   base::RunLoop run_loop;
   CallAcceptFromThreads(
@@ -250,6 +266,21 @@
   run_loop.Run();
 }
 
+TEST_F(WifiLanServerSocketTest, Disconnect_WhileWaitingForAccept_FirewallHole) {
+  const size_t kNumThreads = 3;
+  base::RunLoop run_loop;
+  CallAcceptFromThreads(
+      kNumThreads,
+      /*expected_num_accept_calls_sent_to_tcp_socket=*/kNumThreads,
+      /*expected_success=*/false,
+      /*on_accept_calls_finished=*/run_loop.QuitClosure());
+
+  // Destroying the FirewallHole receiver will trigger the remote's
+  // disconnect handler, which will close the WifiLanServerSocket.
+  firewall_hole_self_owned_receiver_ref_->Close();
+  run_loop.Run();
+}
+
 }  // namespace chrome
 }  // namespace nearby
 }  // namespace location
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 709ab90..02d6029e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5063,6 +5063,7 @@
       "../browser/share/share_submenu_model_unittest.cc",
       "../browser/speech/speech_recognition_service_factory_unittest.cc",
       "../browser/support_tool/support_tool_handler_unittest.cc",
+      "../browser/support_tool/system_log_source_data_collector_adaptor_unittest.cc",
       "../browser/tab_contents/form_interaction_tab_helper_unittest.cc",
       "../browser/ui/autofill/payments/autofill_dialog_models_unittest.cc",
       "../browser/ui/bookmarks/bookmark_editor_unittest.cc",
@@ -6575,6 +6576,7 @@
       "../browser/nearby_sharing/fast_initiation/fast_initiation_advertiser_unittest.cc",
       "../browser/nearby_sharing/fast_initiation/fast_initiation_scanner_feature_usage_metrics_unittest.cc",
       "../browser/nearby_sharing/fast_initiation/fast_initiation_scanner_unittest.cc",
+      "../browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory_unittest.cc",
       "../browser/nearby_sharing/incoming_frames_reader_unittest.cc",
       "../browser/nearby_sharing/instantmessaging/fake_token_fetcher.cc",
       "../browser/nearby_sharing/instantmessaging/fake_token_fetcher.h",
@@ -6749,6 +6751,7 @@
       "//chromeos/components/quick_answers/public/cpp:cpp",
       "//chromeos/constants",
       "//chromeos/dbus/image_loader",
+      "//chromeos/dbus/permission_broker",
       "//chromeos/dbus/u2f",
       "//chromeos/ui/wm",
       "//components/app_restore:unit_tests",
diff --git a/chrome/test/data/capability_delegation/payment_request_delegation.html b/chrome/test/data/capability_delegation/payment_request_delegation.html
index a37d7ae1..ad1701b 100644
--- a/chrome/test/data/capability_delegation/payment_request_delegation.html
+++ b/chrome/test/data/capability_delegation/payment_request_delegation.html
@@ -20,7 +20,7 @@
       let post_message_options = {};
       post_message_options["targetOrigin"] = "*";
       if (delegate) {
-          post_message_options["delegate"] = "paymentrequest";
+          post_message_options["delegate"] = "payment";
       }
       frames[0].postMessage("try", post_message_options);
       return promise;
diff --git a/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js b/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js
index 54181b87..460a388 100644
--- a/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js
+++ b/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js
@@ -45,6 +45,18 @@
 });
 
 // eslint-disable-next-line no-var
+var AccessCodeCastBrowserProxyTest = class extends AccessCodeCastBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://access-code-cast/test_loader.html?module=access_code_cast/browser_proxy_test.js';
+  }
+};
+
+TEST_F('AccessCodeCastBrowserProxyTest', 'All', function() {
+  mocha.run();
+});
+
+// eslint-disable-next-line no-var
 var AccessCodeCastCodeInputElementTest = class extends AccessCodeCastBrowserTest {
   /** @override */
   get browsePreload() {
@@ -52,10 +64,6 @@
   }
 };
 
-/**
- * This browsertest acts as a thin wrapper to run the unit tests found
- * at code_input_test.js
- */
 TEST_F('AccessCodeCastCodeInputElementTest', 'All', function() {
   mocha.run();
 });
@@ -68,10 +76,6 @@
   }
 };
 
-/**
- * This browsertest acts as a thin wrapper to run the unit tests found
- * at code_input_test.js
- */
 TEST_F('AccessCodeCastErrorMessageElementTest', 'All', function() {
   mocha.run();
 });
diff --git a/chrome/test/data/webui/access_code_cast/access_code_cast_test.js b/chrome/test/data/webui/access_code_cast/access_code_cast_test.js
index 9dbb1b7..ea776a1f 100644
--- a/chrome/test/data/webui/access_code_cast/access_code_cast_test.js
+++ b/chrome/test/data/webui/access_code_cast/access_code_cast_test.js
@@ -47,6 +47,10 @@
     callbackRouterRemote: callbackRouter.$.bindNewPipeAndPassRemote(),
     handler: new TestAccessCodeCastBrowserProxy(
       addResult, castResult, castCallback),
+    async isQrScanningAvailable() {
+      return Promise.resolve(true);
+    },
+    closeDialog() {}
   };
 }
 
diff --git a/chrome/test/data/webui/access_code_cast/browser_proxy_test.js b/chrome/test/data/webui/access_code_cast/browser_proxy_test.js
new file mode 100644
index 0000000..a94e19f
--- /dev/null
+++ b/chrome/test/data/webui/access_code_cast/browser_proxy_test.js
@@ -0,0 +1,157 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {BrowserProxy} from 'chrome://access-code-cast/browser_proxy.js';
+
+suite('BrowserProxyTest', () => {
+  let proxy;
+
+  setup(() => {
+    PolymerTest.clearBody();
+    proxy = BrowserProxy.getInstance();
+  });
+
+  test('close sends correct message', () => {
+    const chromeSend = chrome.send;
+
+    let receivedMessage = 'none';
+
+    // chrome.send is used for test implementation, so we retain its function
+    const mockChromeSend = (message, args) => {
+      receivedMessage = message;
+      chromeSend(message, args);
+    };
+
+    chrome.send = mockChromeSend;
+    proxy.closeDialog();
+    assertEquals(receivedMessage, 'dialogClose');
+
+    // restore chrome.send
+    chrome.send = chromeSend;
+  });
+
+  test('isDialog returns correct values', () => {
+    const chromeGetVariableValue = chrome.getVariableValue;
+
+    let mockChromeGetVariableValue = (message) => {
+      if (message === 'dialogArguments') {
+        return '{testValue: "test"}';
+      }
+    };
+
+    chrome.getVariableValue = mockChromeGetVariableValue;
+
+    assertEquals(proxy.isDialog(), true);
+
+    mockChromeGetVariableValue = (message) => {
+      if (message === 'dialogArguments') {
+        return '';
+      }
+    };
+
+    chrome.getVariableValue = mockChromeGetVariableValue;
+
+    assertEquals(proxy.isDialog(), false);
+
+    // restore chrome.getVariableValue;
+    chrome.getVariableValue = chromeGetVariableValue;
+  });
+
+  test('getDialogArgs returns an object with correct values', () => {
+    const chromeGetVariableValue = chrome.getVariableValue;
+    const testObject = {
+      testString: 'test',
+      testNumber: 123,
+    };
+
+    const testJson = JSON.stringify(testObject);
+    chrome.getVariableValue = (message) => {
+      if (message === 'dialogArguments') {
+        return testJson;
+      }
+    };
+
+    const dialogArgs = proxy.getDialogArgs();
+    assertEquals(dialogArgs.testString, testObject.testString);
+    assertEquals(dialogArgs.testNumber, testObject.testNumber);
+    assertDeepEquals(Object.keys(dialogArgs), Object.keys(testObject));
+
+    chrome.getVariableValue = chromeGetVariableValue;
+  });
+
+  test('isCameraAvailable returns correct values', async () => {
+    const enumerateDevices = navigator.mediaDevices.enumerateDevices;
+
+    const mockDevicesWithCamera = [
+      {kind: 'audioinput'},
+      {kind: 'videoinput'},
+      {kind: 'audioinput'}
+    ];
+
+    const mockDevicesNoCamera = [
+      {kind: 'type1'},
+      {kind: 'type2'},
+    ];
+
+    navigator.mediaDevices.enumerateDevices = async () => {
+      return Promise.resolve(mockDevicesWithCamera);
+    };
+    assertTrue(await proxy.isCameraAvailable());
+
+    navigator.mediaDevices.enumerateDevices = async () => {
+      return Promise.resolve(mockDevicesNoCamera);
+    };
+    assertFalse(await proxy.isCameraAvailable());
+
+    navigator.mediaDevices.enumerateDevices = async () => {
+      return Promise.resolve([]);
+    };
+    assertFalse(await proxy.isCameraAvailable());
+
+    navigator.mediaDevices.enumerateDevices = enumerateDevices;
+  });
+
+  test('isQrScanningAvailable returns correct values', async () => {
+    const getBoolean = loadTimeData.getBoolean;
+    const proxyBarcodeDetector = proxy.isBarcodeApiAvailable;
+    const proxyCamera = proxy.isCameraAvailable;
+
+    const mockGetBooleanEnabled = (message) => {
+      if (message === 'qrScannerEnabled') {
+        return true;
+      }
+    };
+
+    const mockGetBooleanDisabled = (message) => {
+      if (message === 'qrScannerEnabled') {
+        return false;
+      }
+    };
+
+    const mockIsBarcodeApiAvailableTrue = () => true;
+    const mockIsBarcodeApiAvailableFalse = () => false;
+    const mockIsCameraAvailableTrue = () => Promise.resolve(true);
+    const mockIsCameraAvailableFalse = () => Promise.resolve(false);
+
+    // QR scanner feature is enabled
+    loadTimeData.getBoolean = mockGetBooleanEnabled;
+    proxy.isBarcodeApiAvailable = mockIsBarcodeApiAvailableTrue;
+    proxy.isCameraAvailable = mockIsCameraAvailableTrue;
+    assertTrue(await proxy.isQrScanningAvailable());
+
+    // QR scanner feature is disabled
+    loadTimeData.getBoolean = mockGetBooleanDisabled;
+    assertFalse(await proxy.isQrScanningAvailable());
+
+    proxy.isBarcodeApiAvailable = mockIsBarcodeApiAvailableFalse;
+    assertFalse(await proxy.isQrScanningAvailable());
+
+    proxy.isCameraAvailable = mockIsCameraAvailableFalse;
+    assertFalse(await proxy.isQrScanningAvailable());
+
+    loadTimeData.getBoolean = getBoolean;
+    proxy.isBarcodeApiAvailable = proxyBarcodeDetector;
+    proxy.isCameraAvailable = proxyCamera;
+  });
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/personalization_app/test_theme_interface_provider.ts b/chrome/test/data/webui/chromeos/personalization_app/test_theme_interface_provider.ts
index 286d232..c191ee4 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/test_theme_interface_provider.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/test_theme_interface_provider.ts
@@ -5,12 +5,8 @@
 import {ThemeObserverInterface, ThemeObserverRemote, ThemeProviderInterface} from 'chrome://personalization/trusted/personalization_app.mojom-webui.js';
 import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
 
-/**
- * @implements {ThemeProviderInterface}
- * @extends {TestBrowserProxy}
- */
-export class TestThemeProvider extends TestBrowserProxy implements
-    ThemeProviderInterface {
+export class TestThemeProvider extends
+    TestBrowserProxy<ThemeProviderInterface> implements ThemeProviderInterface {
   constructor() {
     super([
       'setThemeObserver',
diff --git a/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts b/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
index eae7b91..9544d94 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
@@ -8,12 +8,9 @@
 import {assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
 
-/**
- * @implements {WallpaperProviderInterface}
- * @extends {TestBrowserProxy}
- */
-export class TestWallpaperProvider extends TestBrowserProxy implements
-    WallpaperProviderInterface {
+export class TestWallpaperProvider extends
+    TestBrowserProxy<WallpaperProviderInterface> implements
+        WallpaperProviderInterface {
   constructor() {
     super([
       'makeTransparent',
diff --git a/chrome/test/data/webui/chromeos/personalization_app/tsconfig_base.json b/chrome/test/data/webui/chromeos/personalization_app/tsconfig_base.json
index 60d2cf74..656123f 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/tsconfig_base.json
+++ b/chrome/test/data/webui/chromeos/personalization_app/tsconfig_base.json
@@ -1,7 +1,6 @@
 {
   "extends": "../../../../../../tools/typescript/tsconfig_base.json",
   "compilerOptions": {
-    "allowJs": true,
     "typeRoots": [
        "../../../../../../third_party/node/node_modules/@types"
     ]
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_calibration_failed_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_calibration_failed_page_test.js
index b4aad61..76cd545 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_calibration_failed_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_calibration_failed_page_test.js
@@ -196,4 +196,40 @@
     await clickRetryCalibrationButton();
     assertEquals(1, startCalibrationCalls);
   });
+
+  test('ComponentChipsDisabled', async () => {
+    await initializeCalibrationPage(fakeCalibrationComponents);
+
+    const cameraComponent =
+        component.shadowRoot.querySelector('#componentCamera');
+    const batteryComponent =
+        component.shadowRoot.querySelector('#componentBattery');
+    const baseAccelerometerComponent =
+        component.shadowRoot.querySelector('#componentBaseAccelerometer');
+    const lidAccelerometerComponent =
+        component.shadowRoot.querySelector('#componentLidAccelerometer');
+    const touchpadComponent =
+        component.shadowRoot.querySelector('#componentTouchpad');
+    assertFalse(cameraComponent.disabled);
+    assertFalse(batteryComponent.disabled);
+    assertFalse(baseAccelerometerComponent.disabled);
+    assertFalse(lidAccelerometerComponent.disabled);
+    assertFalse(touchpadComponent.disabled);
+    component.allButtonsDisabled = true;
+    assertTrue(cameraComponent.disabled);
+    assertTrue(batteryComponent.disabled);
+    assertTrue(baseAccelerometerComponent.disabled);
+    assertTrue(lidAccelerometerComponent.disabled);
+    assertTrue(touchpadComponent.disabled);
+  });
+
+  test('RetryCalibrationButtonDisabled', async () => {
+    await initializeCalibrationPage(fakeCalibrationComponents);
+
+    const retryButton =
+        component.shadowRoot.querySelector('#retryCalibrationButton');
+    assertFalse(retryButton.disabled);
+    component.allButtonsDisabled = true;
+    assertTrue(retryButton.disabled);
+  });
 }
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_device_information_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_device_information_page_test.js
index 7d5e585..e8c32d4 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_device_information_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_device_information_page_test.js
@@ -189,22 +189,25 @@
 
     const serialNumberInput =
         component.shadowRoot.querySelector('#serialNumber');
-    const serialNumberButton =
-        component.shadowRoot.querySelector('#resetSerialNumber');
     const regionSelect = component.shadowRoot.querySelector('#regionSelect');
-    const regionButton = component.shadowRoot.querySelector('#resetRegion');
     const skuSelect = component.shadowRoot.querySelector('#skuSelect');
-    const skuButton = component.shadowRoot.querySelector('#resetSku');
+    const dramSelect = component.shadowRoot.querySelector('#dramPartNumber');
+    const whiteLabelSelect =
+        component.shadowRoot.querySelector('#whiteLabelSelect');
 
     component.allButtonsDisabled = false;
     assertFalse(serialNumberInput.disabled);
     assertFalse(regionSelect.disabled);
     assertFalse(skuSelect.disabled);
+    assertFalse(dramSelect.disabled);
+    assertFalse(whiteLabelSelect.disabled);
 
     component.allButtonsDisabled = true;
     assertTrue(serialNumberInput.disabled);
     assertTrue(regionSelect.disabled);
     assertTrue(skuSelect.disabled);
+    assertTrue(dramSelect.disabled);
+    assertTrue(whiteLabelSelect.disabled);
   });
 
   test(
@@ -212,6 +215,7 @@
       async () => {
         await initializeReimagingDeviceInformationPage();
 
+        component.allButtonsDisabled = false;
         let dramPartNumber = fakeDramPartNumber + 'new part number';
         const dramPartNumberComponent =
             component.shadowRoot.querySelector('#dramPartNumber');
diff --git a/chrome/test/data/webui/settings/privacy_review_page_test.ts b/chrome/test/data/webui/settings/privacy_review_page_test.ts
index 284d8e15..c4f5dcaf 100644
--- a/chrome/test/data/webui/settings/privacy_review_page_test.ts
+++ b/chrome/test/data/webui/settings/privacy_review_page_test.ts
@@ -260,6 +260,7 @@
     assertQueryParameter(PrivacyReviewStep.MSBB);
     assertCardComponentsVisible({
       isSettingFooterVisibleExpected: true,
+      isBackButtonVisibleExpected: true,
       isMsbbFragmentVisibleExpected: true,
     });
     assertStepIndicatorModel(0);
@@ -352,6 +353,15 @@
     assertMsbbCardVisible();
   });
 
+  test('msbbBackNavigation', function() {
+    navigateToStep(PrivacyReviewStep.MSBB);
+    assertMsbbCardVisible();
+
+    page.shadowRoot!.querySelector<HTMLElement>('#backButton')!.click();
+    flush();
+    assertWelcomeCardVisible();
+  });
+
   test('msbbForwardNavigationSyncOn', function() {
     navigateToStep(PrivacyReviewStep.MSBB);
     setSyncEnabled(true);
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index ae74406d..cb4e89e 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -639,6 +639,7 @@
 
       deps += [
         "//chrome/common/mac:launchd",
+        "//chrome/updater/mac:ksadmin_implementation",
         "//third_party/ocmock",
       ]
 
diff --git a/chrome/updater/app/app_server.cc b/chrome/updater/app/app_server.cc
index c47a29b5..0a95493 100644
--- a/chrome/updater/app/app_server.cc
+++ b/chrome/updater/app/app_server.cc
@@ -124,10 +124,10 @@
   if (!prefs_)
     return;
 
-  if (ShouldUninstall(
-          base::MakeRefCounted<PersistedData>(prefs_->GetPrefService())
-              ->GetAppIds(),
-          server_starts_)) {
+  auto persisted_data =
+      base::MakeRefCounted<PersistedData>(prefs_->GetPrefService());
+  if (ShouldUninstall(persisted_data->GetAppIds(), server_starts_,
+                      persisted_data->GetHadApps())) {
     base::CommandLine command_line(
         base::CommandLine::ForCurrentProcess()->GetProgram());
     command_line.AppendSwitch(kUninstallIfUnusedSwitch);
diff --git a/chrome/updater/app/app_uninstall.cc b/chrome/updater/app/app_uninstall.cc
index 396a8a7..82f3415 100644
--- a/chrome/updater/app/app_uninstall.cc
+++ b/chrome/updater/app/app_uninstall.cc
@@ -133,10 +133,11 @@
 
   if (command_line->HasSwitch(kUninstallIfUnusedSwitch)) {
     CHECK(global_prefs_);
+    auto persisted_data =
+        base::MakeRefCounted<PersistedData>(global_prefs_->GetPrefService());
     const bool should_uninstall = ShouldUninstall(
-        base::MakeRefCounted<PersistedData>(global_prefs_->GetPrefService())
-            ->GetAppIds(),
-        global_prefs_->CountServerStarts());
+        persisted_data->GetAppIds(), global_prefs_->CountServerStarts(),
+        persisted_data->GetHadApps());
     VLOG(1) << "ShouldUninstall returned: " << should_uninstall;
     if (should_uninstall) {
       base::ThreadPool::PostTaskAndReplyWithResult(
diff --git a/chrome/updater/app/app_utils.cc b/chrome/updater/app/app_utils.cc
index b304447..5c8c2ca 100644
--- a/chrome/updater/app/app_utils.cc
+++ b/chrome/updater/app/app_utils.cc
@@ -9,8 +9,10 @@
 namespace updater {
 
 bool ShouldUninstall(const std::vector<std::string>& app_ids,
-                     int server_starts) {
-  return app_ids.size() <= 1 && server_starts > kMaxServerStartsBeforeFirstReg;
+                     int server_starts,
+                     bool had_apps) {
+  return app_ids.size() <= 1 &&
+         (server_starts > kMaxServerStartsBeforeFirstReg || had_apps);
 }
 
 }  // namespace updater
diff --git a/chrome/updater/app/app_utils.h b/chrome/updater/app/app_utils.h
index a8690d6..8823eb4 100644
--- a/chrome/updater/app/app_utils.h
+++ b/chrome/updater/app/app_utils.h
@@ -9,8 +9,15 @@
 #include <vector>
 
 namespace updater {
+
+// Returns true if the updater should uninstall itself. `app_ids` is the set of
+// registered applications, `server_starts` is the number of times the server
+// has launched, and `had_apps` is a bool indicating whether there has ever been
+// an application (other than the updater itself) registered for updates.
 bool ShouldUninstall(const std::vector<std::string>& app_ids,
-                     int server_starts);
+                     int server_starts,
+                     bool had_apps);
+
 }  // namespace updater
 
 #endif  // CHROME_UPDATER_APP_APP_UTILS_H_
diff --git a/chrome/updater/mac/BUILD.gn b/chrome/updater/mac/BUILD.gn
index 8d298bf..cbfe4f3 100644
--- a/chrome/updater/mac/BUILD.gn
+++ b/chrome/updater/mac/BUILD.gn
@@ -137,20 +137,29 @@
   ]
 }
 
-executable("ksadmin") {
-  output_name = "ksadmin"
+source_set("ksadmin_implementation") {
   sources = [
     "keystone/ksadmin.h",
     "keystone/ksadmin.mm",
-    "keystone/ksadmin_main.cc",
   ]
 
   deps = [
     "//base",
     "//chrome/updater:base",
-    "//chrome/updater:constants_prod",
     "//chrome/updater:version_header",
   ]
+}
+
+executable("ksadmin") {
+  output_name = "ksadmin"
+  sources = [ "keystone/ksadmin_main.cc" ]
+
+  public_deps = [ ":ksadmin_implementation" ]
+
+  deps = [
+    "//base",
+    "//chrome/updater:constants_prod",
+  ]
 
   frameworks = [ "CoreFoundation.framework" ]
 
diff --git a/chrome/updater/mac/keystone/ksadmin.h b/chrome/updater/mac/keystone/ksadmin.h
index 989aaf0..6ae8fe3 100644
--- a/chrome/updater/mac/keystone/ksadmin.h
+++ b/chrome/updater/mac/keystone/ksadmin.h
@@ -5,9 +5,21 @@
 #ifndef CHROME_UPDATER_MAC_KEYSTONE_KSADMIN_H_
 #define CHROME_UPDATER_MAC_KEYSTONE_KSADMIN_H_
 
+#include <string>
+
+#include "base/containers/flat_map.h"
+
 namespace updater {
 
-int KSAdminAppMain(int argc, char* argv[]);
+namespace ksadmin_internal {
+
+// Exports the function for testing purpose.
+base::flat_map<std::string, std::string> ParseCommandLine(int argc,
+                                                          const char* argv[]);
+
+}  // namespace ksadmin_internal
+
+int KSAdminAppMain(int argc, const char* argv[]);
 
 }  // namespace updater
 
diff --git a/chrome/updater/mac/keystone/ksadmin.mm b/chrome/updater/mac/keystone/ksadmin.mm
index 6b2ec453..f6491d26 100644
--- a/chrome/updater/mac/keystone/ksadmin.mm
+++ b/chrome/updater/mac/keystone/ksadmin.mm
@@ -41,28 +41,8 @@
 #include "chrome/updater/util.h"
 
 namespace updater {
-namespace {
 
-constexpr char kCommandDelete[] = "delete";
-constexpr char kCommandInstall[] = "install";
-constexpr char kCommandList[] = "list";
-constexpr char kCommandKsadminVersion[] = "ksadmin-version";
-constexpr char kCommandPrintTag[] = "print-tag";
-constexpr char kCommandPrintTickets[] = "print-tickets";
-constexpr char kCommandRegister[] = "register";
-constexpr char kCommandSystemStore[] = "system-store";
-constexpr char kCommandUserInitiated[] = "user-initiated";
-constexpr char kCommandUserStore[] = "user-store";
-constexpr char kCommandBrandKey[] = "brand-key";
-constexpr char kCommandBrandPath[] = "brand-path";
-constexpr char kCommandProductId[] = "productid";
-constexpr char kCommandTag[] = "tag";
-constexpr char kCommandTagKey[] = "tag-key";
-constexpr char kCommandTagPath[] = "tag-path";
-constexpr char kCommandVersion[] = "version";
-constexpr char kCommandVersionKey[] = "version-key";
-constexpr char kCommandVersionPath[] = "version-path";
-constexpr char kCommandXCPath[] = "xcpath";
+namespace ksadmin_internal {
 
 // base::CommandLine can't be used because it enforces that all switches are
 // lowercase, but ksadmin has case-sensitive switches. This argument parser
@@ -70,7 +50,7 @@
 // `ksadmin --register --productid com.goog.chrome -v 1.2.3.4 e` to
 // `{"register": "", "productid": "com.goog.chrome", "v": "1.2.3.4", "e": ""}`.
 base::flat_map<std::string, std::string> ParseCommandLine(int argc,
-                                                          char* argv[]) {
+                                                          const char* argv[]) {
   base::flat_map<std::string, std::string> result;
   std::string last_arg;
   for (int i = 1; i < argc; ++i) {
@@ -102,6 +82,31 @@
   return result;
 }
 
+}  // namespace ksadmin_internal
+
+namespace {
+
+constexpr char kCommandDelete[] = "delete";
+constexpr char kCommandInstall[] = "install";
+constexpr char kCommandList[] = "list";
+constexpr char kCommandKsadminVersion[] = "ksadmin-version";
+constexpr char kCommandPrintTag[] = "print-tag";
+constexpr char kCommandPrintTickets[] = "print-tickets";
+constexpr char kCommandRegister[] = "register";
+constexpr char kCommandSystemStore[] = "system-store";
+constexpr char kCommandUserInitiated[] = "user-initiated";
+constexpr char kCommandUserStore[] = "user-store";
+constexpr char kCommandBrandKey[] = "brand-key";
+constexpr char kCommandBrandPath[] = "brand-path";
+constexpr char kCommandProductId[] = "productid";
+constexpr char kCommandTag[] = "tag";
+constexpr char kCommandTagKey[] = "tag-key";
+constexpr char kCommandTagPath[] = "tag-path";
+constexpr char kCommandVersion[] = "version";
+constexpr char kCommandVersionKey[] = "version-key";
+constexpr char kCommandVersionPath[] = "version-path";
+constexpr char kCommandXCPath[] = "xcpath";
+
 bool HasSwitch(const std::string& arg,
                const base::flat_map<std::string, std::string>& switches) {
   if (base::Contains(switches, arg))
@@ -455,11 +460,11 @@
 
 }  // namespace
 
-int KSAdminAppMain(int argc, char* argv[]) {
+int KSAdminAppMain(int argc, const char* argv[]) {
   base::AtExitManager exit_manager;
   base::CommandLine::Init(argc, argv);
   base::flat_map<std::string, std::string> command_line =
-      ParseCommandLine(argc, argv);
+      ksadmin_internal::ParseCommandLine(argc, argv);
   updater::InitLogging(Scope(command_line), FILE_PATH_LITERAL("updater.log"));
   base::SingleThreadTaskExecutor main_task_executor(base::MessagePumpType::UI);
   return base::MakeRefCounted<KSAdminApp>(command_line)->Run();
diff --git a/chrome/updater/mac/keystone/ksadmin_main.cc b/chrome/updater/mac/keystone/ksadmin_main.cc
index f96128ca..7e61660f 100644
--- a/chrome/updater/mac/keystone/ksadmin_main.cc
+++ b/chrome/updater/mac/keystone/ksadmin_main.cc
@@ -4,6 +4,6 @@
 
 #include "chrome/updater/mac/keystone/ksadmin.h"
 
-int main(int argc, char* argv[]) {
+int main(int argc, const char* argv[]) {
   return updater::KSAdminAppMain(argc, argv);
 }
diff --git a/chrome/updater/mac/keystone/ksadmin_unittest.cc b/chrome/updater/mac/keystone/ksadmin_unittest.cc
index bb38885..6f85094b 100644
--- a/chrome/updater/mac/keystone/ksadmin_unittest.cc
+++ b/chrome/updater/mac/keystone/ksadmin_unittest.cc
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/updater/mac/keystone/ksadmin.h"
+
 #include <string>
 #include <vector>
 
+#include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
@@ -50,4 +53,41 @@
   ASSERT_EQ(out, base::StrCat({kUpdaterVersion, "\n"}));
 }
 
+TEST(KSAdminTest, ParseCommandLine) {
+  const char* argv[] = {"ksadmin",  "--register",
+                        "-P",       "com.google.kipple",
+                        "-v",       "1.2.3.4",
+                        "--xcpath", "/Applications/GoogleKipple.app",
+                        "-u",       "https://tools.google.com/service/update2"};
+
+  base::flat_map<std::string, std::string> arg_map =
+      ksadmin_internal::ParseCommandLine(std::size(argv), argv);
+  EXPECT_EQ(arg_map.size(), size_t{5});
+  EXPECT_EQ(arg_map["register"], "");
+  EXPECT_EQ(arg_map["P"], "com.google.kipple");
+  EXPECT_EQ(arg_map["v"], "1.2.3.4");
+  EXPECT_EQ(arg_map["xcpath"], "/Applications/GoogleKipple.app");
+  EXPECT_EQ(arg_map["u"], "https://tools.google.com/service/update2");
+}
+
+TEST(KSAdminTest, ParseCommandLine_DiffByCase) {
+  const char* argv[] = {"ksadmin", "-k", "-K", "Tag"};
+
+  base::flat_map<std::string, std::string> arg_map =
+      ksadmin_internal::ParseCommandLine(std::size(argv), argv);
+  EXPECT_EQ(arg_map.size(), size_t{2});
+  EXPECT_EQ(arg_map["k"], "");
+  EXPECT_EQ(arg_map["K"], "Tag");
+}
+
+TEST(KSAdminTest, ParseCommandLine_CombinedShortOptions) {
+  const char* argv[] = {"ksadmin", "-pP", "com.google.Chrome"};
+
+  base::flat_map<std::string, std::string> arg_map =
+      ksadmin_internal::ParseCommandLine(std::size(argv), argv);
+  EXPECT_EQ(arg_map.size(), size_t{2});
+  EXPECT_EQ(arg_map["p"], "");
+  EXPECT_EQ(arg_map["P"], "com.google.Chrome");
+}
+
 }  // namespace updater
diff --git a/chrome/updater/persisted_data.cc b/chrome/updater/persisted_data.cc
index 9e8273a..a9eb029 100644
--- a/chrome/updater/persisted_data.cc
+++ b/chrome/updater/persisted_data.cc
@@ -6,11 +6,13 @@
 
 #include "base/check_op.h"
 #include "base/files/file_path.h"
+#include "base/sequence_checker.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/updater/registration_data.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 
@@ -26,6 +28,8 @@
 constexpr char kBP[] = "bp";    // Key for storing brand path.
 constexpr char kAP[] = "ap";    // Key for storing ap.
 
+constexpr char kHadApps[] = "had_apps";
+
 }  // namespace
 
 namespace updater {
@@ -197,4 +201,21 @@
   GetOrCreateAppKey(id, update.Get())->SetStringKey(key, value);
 }
 
+bool PersistedData::GetHadApps() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return pref_service_ && pref_service_->GetBoolean(kHadApps);
+}
+
+void PersistedData::SetHadApps() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (pref_service_)
+    pref_service_->SetBoolean(kHadApps, true);
+}
+
+// Register persisted data prefs, except for kPersistedDataPreference.
+// kPersistedDataPreference is registered by update_client::RegisterPrefs.
+void RegisterPersistedDataPrefs(scoped_refptr<PrefRegistrySimple> registry) {
+  registry->RegisterBooleanPref(kHadApps, false);
+}
+
 }  // namespace updater
diff --git a/chrome/updater/persisted_data.h b/chrome/updater/persisted_data.h
index 7aa46b70..49ecb34a 100644
--- a/chrome/updater/persisted_data.h
+++ b/chrome/updater/persisted_data.h
@@ -13,6 +13,7 @@
 #include "base/sequence_checker.h"
 
 class PrefService;
+class PrefRegistrySimple;
 
 namespace base {
 class FilePath;
@@ -77,6 +78,11 @@
   // application has a valid version.
   std::vector<std::string> GetAppIds() const;
 
+  // HadApps is set when the updater processes a registration for an app other
+  // than itself, and is never unset, even if the app is uninstalled.
+  bool GetHadApps() const;
+  void SetHadApps();
+
  private:
   friend class base::RefCountedThreadSafe<PersistedData>;
   ~PersistedData();
@@ -96,6 +102,8 @@
   raw_ptr<PrefService> pref_service_ = nullptr;  // Not owned by this class.
 };
 
+void RegisterPersistedDataPrefs(scoped_refptr<PrefRegistrySimple> registry);
+
 }  // namespace updater
 
 #endif  // CHROME_UPDATER_PERSISTED_DATA_H_
diff --git a/chrome/updater/prefs.cc b/chrome/updater/prefs.cc
index 1d39808..7e8b6c6 100644
--- a/chrome/updater/prefs.cc
+++ b/chrome/updater/prefs.cc
@@ -15,6 +15,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/waitable_event.h"
 #include "chrome/updater/constants.h"
+#include "chrome/updater/persisted_data.h"
 #include "chrome/updater/prefs_impl.h"
 #include "chrome/updater/updater_scope.h"
 #include "chrome/updater/util.h"
@@ -111,6 +112,7 @@
   pref_registry->RegisterStringPref(kPrefActiveVersion, "0");
   pref_registry->RegisterTimePref(kPrefUpdateTime, base::Time());
   pref_registry->RegisterIntegerPref(kPrefServerStarts, 0);
+  RegisterPersistedDataPrefs(pref_registry);
 
   return base::MakeRefCounted<UpdaterPrefsImpl>(
       std::move(lock), pref_service_factory.Create(pref_registry));
@@ -130,6 +132,7 @@
   update_client::RegisterPrefs(pref_registry.get());
   pref_registry->RegisterBooleanPref(kPrefQualified, false);
   pref_registry->RegisterTimePref(kPrefUpdateTime, base::Time());
+  RegisterPersistedDataPrefs(pref_registry);
 
   return base::MakeRefCounted<UpdaterPrefsImpl>(
       nullptr, pref_service_factory.Create(pref_registry));
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index ba86247f..468fac1 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -499,8 +499,6 @@
   WaitForUpdaterExit();
   ExpectInstalled();
 
-  // TODO(crbug.com/1270520) - use a switch that can uninstall immediately if
-  // unused, instead of requiring server starts.
   SetServerStarts(24);
 
   // Uninstall the idle updater.
@@ -545,7 +543,6 @@
   RegisterApp("test1");
   ExpectInstalled();
   WaitForUpdaterExit();
-  SetServerStarts(24);
   RunWake(0);
   WaitForUpdaterExit();
   ExpectInstalled();
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc
index ca8ab349..65678d0 100644
--- a/chrome/updater/update_service_impl.cc
+++ b/chrome/updater/update_service_impl.cc
@@ -217,6 +217,9 @@
     base::OnceCallback<void(const RegistrationResponse&)> callback) {
   VLOG(1) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (request.app_id != kUpdaterAppId) {
+    persisted_data_->SetHadApps();
+  }
   base::Version current_version =
       persisted_data_->GetProductVersion(request.app_id);
   if (current_version.IsValid() &&
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 9bf8ab86..d1227c2 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "4.85",
-  "log_list_timestamp": "2022-01-10T01:34:22Z",
+  "version": "4.87",
+  "log_list_timestamp": "2022-01-12T01:33:59Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/feed/core/common/pref_names.h b/components/feed/core/common/pref_names.h
index dbb6c4b6..d4eeb37 100644
--- a/components/feed/core/common/pref_names.h
+++ b/components/feed/core/common/pref_names.h
@@ -19,6 +19,7 @@
 // The pref name for the feed host override auth token.
 extern const char kHostOverrideBlessNonce[];
 
+// TODO(b/213622639): This pref is unused and should be cleared / removed.
 // The pref name for the bit that determines whether the conditions are reached
 // to enable the upload of click and view actions in the feed with the notice
 // card when using the feature kInterestFeedConditionalClickAndViewActionUpload.
diff --git a/components/feed/core/proto/v2/store.proto b/components/feed/core/proto/v2/store.proto
index 13d6830..da7ee4a 100644
--- a/components/feed/core/proto/v2/store.proto
+++ b/components/feed/core/proto/v2/store.proto
@@ -54,6 +54,10 @@
   repeated feedwire.ContentId shared_state_ids = 6;
   // Was this feed signed in.
   bool signed_in = 7;
+  // If signed_in, this is the account gaia tied to this stream data.
+  string gaia = 13;
+  // If signed_in, this is the account email tied to this stream data.
+  string email = 14;
   // Is activity logging enabled?
   bool logging_enabled = 8;
   // Has the privacy notice been fulfilled?
diff --git a/components/feed/core/v2/BUILD.gn b/components/feed/core/v2/BUILD.gn
index 74b51b4..dd92c173 100644
--- a/components/feed/core/v2/BUILD.gn
+++ b/components/feed/core/v2/BUILD.gn
@@ -13,6 +13,7 @@
     "public/feed_api.h",
     "public/feed_service.h",
     "public/feed_stream_surface.h",
+    "public/logging_parameters.h",
     "public/persistent_key_value_store.h",
     "public/persistent_key_value_store.h",
     "public/refresh_task_scheduler.h",
@@ -60,6 +61,7 @@
     "public/feed_api.cc",
     "public/feed_service.cc",
     "public/feed_stream_surface.cc",
+    "public/logging_parameters.cc",
     "public/persistent_key_value_store.cc",
     "public/public_types.cc",
     "public/stream_type.cc",
@@ -74,8 +76,6 @@
     "stream/privacy_notice_card_tracker.h",
     "stream/unread_content_notifier.cc",
     "stream/unread_content_notifier.h",
-    "stream/upload_criteria.cc",
-    "stream/upload_criteria.h",
     "stream_model.cc",
     "stream_model.h",
     "stream_model/ephemeral_change.cc",
@@ -197,6 +197,7 @@
     "proto_util_unittest.cc",
     "protocol_translator_unittest.cc",
     "public/feed_service_unittest.cc",
+    "public/logging_parameters_unittest.cc",
     "public/public_types_unittest.cc",
     "request_throttler_unittest.cc",
     "scheduling_unittest.cc",
diff --git a/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc b/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
index 45d8d5b..20774f3f 100644
--- a/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
@@ -31,17 +31,6 @@
   StreamModelUpdateRequestGenerator model_generator_;
 };
 
-class FeedStreamConditionalActionsUploadTest : public FeedApiNoticeCardTest {
- public:
-  FeedStreamConditionalActionsUploadTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        feed::kInterestFeedV2ClicksAndViewsConditionalUpload);
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
 TEST_F(FeedApiNoticeCardTest, LoadStreamSendsNoticeCardAcknowledgement) {
   response_translator_.InjectResponse(model_generator_.MakeFirstPage());
 
@@ -76,162 +65,6 @@
                   .notice_card_acknowledged());
 }
 
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       NoActionsUploadUntilReachedConditions) {
-  // Tests the flow where we:
-  //   (1) Perform a ThereAndBackAgain action and a View action while upload
-  //   isn't enabled => (2) Attempt an upload while the upload conditions aren't
-  //   reached => (3) Reach upload conditions => (4) Perform another View action
-  //   that should be dropped => (5) Simulate the backgrounding of the app to
-  //   enable actions upload => (6) Trigger an upload which will upload the
-  //   stored ThereAndBackAgain action.
-
-  // WebFeed stream is only fetched when there's a subscription.
-  network_.InjectListWebFeedsResponse({MakeWireWebFeed("cats")});
-  response_translator_.InjectResponse(model_generator_.MakeFirstPage());
-  TestWebFeedSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Process the view action and the ThereAndBackAgain action while the upload
-  // conditions aren't reached.
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  // Verify that the view action was dropped.
-  ASSERT_EQ(0ul, ReadStoredActions(stream_->GetStore()).size());
-
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  // Verify that the ThereAndBackAgain action is in the action store.
-  ASSERT_EQ(1ul, ReadStoredActions(stream_->GetStore()).size());
-
-  // Attempt an upload.
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-  // Verify that no upload is done because the conditions aren't reached.
-  EXPECT_EQ(0, network_.GetActionRequestCount());
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(0).slice().slice_id());
-
-  // Verify that the view action is still dropped because we haven't
-  // transitioned out of the current surface.
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1ul, ReadStoredActions(stream_->GetStore()).size());
-
-  // Enable the upload bit and trigger the upload of actions.
-  surface.Detach();
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify that the ThereAndBackAgain action was uploaded but not the view
-  // action.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest, EnableUploadOnSurfaceAttached) {
-  response_translator_.InjectResponse(model_generator_.MakeFirstPage());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Perform a ThereAndBackAgain action.
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(0).slice().slice_id());
-
-  // Attach a new surface to update the bit to enable uploads.
-  TestForYouSurface surface2(stream_.get());
-
-  // Trigger an upload through load more to isolate the effect of the on-attach
-  // event on enabling uploads.
-  response_translator_.InjectResponse(model_generator_.MakeNextPage());
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  // Verify that the ThereAndBackAgain action was uploaded.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest, EnableUploadOnEnterBackground) {
-  response_translator_.InjectResponse(model_generator_.MakeFirstPage());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Perform a ThereAndBackAgain action.
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(0).slice().slice_id());
-
-  surface.Detach();
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify that the ThereAndBackAgain action was uploaded.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       AllowActionsUploadWhenNoticeCardNotPresentRegardlessOfConditions) {
-  model_generator_.privacy_notice_fulfilled = false;
-  response_translator_.InjectResponse(model_generator_.MakeFirstPage());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Process the view action and the ThereAndBackAgain action while the upload
-  // conditions aren't reached.
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Trigger an upload through a query.
-  surface.Detach();
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify the ThereAndBackAgain action and the view action were uploaded.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(2, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       ResetTheUploadEnableBitsOnClearAll) {
-  response_translator_.InjectResponse(model_generator_.MakeFirstPage());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(0).slice().slice_id());
-  surface.Detach();
-  stream_->OnEnterBackground();
-  ASSERT_TRUE(stream_->CanUploadActions());
-
-  // Trigger a ClearAll, and ensure actions cannot be uploaded until conditions
-  // are reached again.
-  stream_->OnSignedOut();
-  WaitForIdleTaskQueue();
-  ASSERT_FALSE(stream_->CanUploadActions());
-}
-
 TEST_F(FeedApiNoticeCardTest, LoadStreamUpdateNoticeCardFulfillmentHistogram) {
   base::HistogramTester histograms;
 
@@ -266,66 +99,6 @@
                                1, 1);
 }
 
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       DontTriggerActionsUploadWhenWasNotSignedIn) {
-  auto update_request = model_generator_.MakeFirstPage();
-  update_request->stream_data.set_signed_in(false);
-  response_translator_.InjectResponse(std::move(update_request));
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Try to reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-
-  // Try to trigger an upload through a query.
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify that even if the conditions were reached, the pref that enables the
-  // upload wasn't set to true because the latest refresh request wasn't signed
-  // in.
-  ASSERT_FALSE(stream_->CanUploadActions());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       LoadMoreDoesntUpdateNoticeCardPrefAndHistogram) {
-  // The initial stream load has the notice card.
-  response_translator_.InjectResponse(model_generator_.MakeFirstPage());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Inject a response for the LoadMore fetch that doesn't have the notice card.
-  // It shouldn't overwrite the notice card pref.
-  model_generator_.privacy_notice_fulfilled = false;
-  response_translator_.InjectResponse(model_generator_.MakeNextPage());
-
-  // Start tracking histograms after the initial stream load to isolate the
-  // effect of load more.
-  base::HistogramTester histograms;
-
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  // Process a view action that should be dropped because the upload of actions
-  // is still disabled because there is still a notice card.
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Trigger an upload.
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify that there were no uploads.
-  EXPECT_EQ(0, network_.GetActionRequestCount());
-
-  // Verify that the notice card fulfillment histogram isn't recorded for load
-  // more.
-  histograms.ExpectTotalCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
-                              0);
-}
-
 }  // namespace
 }  // namespace test
 }  // namespace feed
diff --git a/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc b/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
index da4c51d..c280ca9 100644
--- a/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
@@ -394,8 +394,8 @@
 
 TEST_F(FeedApiReliabilityLoggingTest, UploadActions) {
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  stream_->UploadAction(MakeFeedAction(1ul), /*upload_now=*/false,
-                        base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(),
+                        /*upload_now=*/false, base::DoNothing());
   TestForYouSurface surface(stream_.get());
   WaitForIdleTaskQueue();
 
@@ -451,4 +451,4 @@
 
 }  // namespace
 }  // namespace test
-}  // namespace feed
\ No newline at end of file
+}  // namespace feed
diff --git a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
index 3038df3..5208108 100644
--- a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/feed/core/v2/public/feed_api.h"
 #include "components/feed/core/v2/public/feed_service.h"
 #include "components/feed/core/v2/public/stream_type.h"
+#include "components/feed/core/v2/public/types.h"
 #include "components/feed/core/v2/scheduling.h"
 #include "components/feed/core/v2/stream/notice_card_tracker.h"
 #include "components/feed/core/v2/test/callback_receiver.h"
@@ -127,12 +128,14 @@
 }
 
 TEST_F(FeedApiTest, SurfaceReceivesInitialContent) {
-  {
-    auto model = CreateStreamModel();
-    model->Update(MakeTypicalInitialModelState());
-    stream_->LoadModelForTesting(kForYouStream, std::move(model));
-  }
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  // Use `the_first_surface` to force loading content.
+  TestForYouSurface the_first_surface(stream_.get());
+  WaitForIdleTaskQueue();
+
   TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
   ASSERT_TRUE(surface.initial_state);
   const feedui::StreamUpdate& initial_state = surface.initial_state.value();
   ASSERT_EQ(2, initial_state.updated_slices().size());
@@ -156,13 +159,10 @@
 }
 
 TEST_F(FeedApiTest, SurfaceReceivesInitialContentLoadedAfterAttach) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
   TestForYouSurface surface(stream_.get());
   ASSERT_FALSE(surface.initial_state);
-  {
-    auto model = CreateStreamModel();
-    model->Update(MakeTypicalInitialModelState());
-    stream_->LoadModelForTesting(kForYouStream, std::move(model));
-  }
+  WaitForIdleTaskQueue();
 
   ASSERT_EQ("loading -> [user@foo] 2 slices", surface.DescribeUpdates());
   const feedui::StreamUpdate& initial_state = surface.initial_state.value();
@@ -201,8 +201,7 @@
   const feedui::StreamUpdate& initial_state = surface.initial_state.value();
   const feedui::StreamUpdate& update = surface.update.value();
 
-  ASSERT_EQ("[View logging only user@foo] 2 slices -> 2 slices",
-            surface.DescribeUpdates());
+  ASSERT_EQ("2 slices -> 2 slices", surface.DescribeUpdates());
   // First slice is just an ID that matches the old 1st slice ID.
   EXPECT_EQ(initial_state.updated_slices(0).slice().slice_id(),
             update.updated_slices(0).slice_id());
@@ -237,8 +236,7 @@
 
   // The last update should have only one new piece of content.
   // This verifies the current content set is tracked properly.
-  ASSERT_EQ("[View logging only user@foo] 2 slices -> 3 slices -> 4 slices",
-            surface.DescribeUpdates());
+  ASSERT_EQ("2 slices -> 3 slices -> 4 slices", surface.DescribeUpdates());
 
   ASSERT_EQ(4, surface.update->updated_slices().size());
   EXPECT_FALSE(surface.update->updated_slices(0).has_slice());
@@ -783,7 +781,7 @@
 
   // Validate that the network request was sent as signed out.
   ASSERT_EQ(1, network_.send_query_call_count);
-  EXPECT_EQ("", network_.last_gaia);
+  EXPECT_EQ(AccountInfo{}, network_.last_account_info);
   EXPECT_TRUE(network_.query_request_sent->feed_request()
                   .client_info()
                   .chrome_client_info()
@@ -791,10 +789,7 @@
                   .empty());
 
   // Validate the downstream consumption of the response.
-  // TODO(crbug.com/1268575): We should disable view logging for the signed-out
-  // feed even if the user is signed-in.
-  EXPECT_EQ("loading -> [View logging only user@foo] 2 slices",
-            surface.DescribeUpdates());
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
   EXPECT_EQ(kSessionId, stream_->GetMetadata().session_id().token());
   EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())->signed_in());
 
@@ -811,7 +806,7 @@
   // Validate that the network request was sent as signed out and
   // contained the session id.
   ASSERT_EQ(2, network_.send_query_call_count);
-  EXPECT_EQ("", network_.last_gaia);
+  EXPECT_EQ(AccountInfo{}, network_.last_account_info);
   EXPECT_EQ(kSessionId, stream_->GetMetadata().session_id().token());
   EXPECT_EQ(network_.query_request_sent->feed_request()
                 .client_info()
@@ -832,7 +827,7 @@
 
   // Validate that a signed-in request was sent.
   ASSERT_EQ(3, network_.send_query_call_count);
-  EXPECT_NE("", network_.last_gaia);
+  EXPECT_NE(AccountInfo{}, network_.last_account_info);
 
   // The model should now be in the signed-in state.
   EXPECT_TRUE(stream_->GetModel(kForYouStream)->signed_in());
@@ -853,7 +848,7 @@
   WaitForIdleTaskQueue();
 
   ASSERT_EQ(1, network_.send_query_call_count);
-  EXPECT_NE("", network_.last_gaia);
+  EXPECT_NE(AccountInfo{}, network_.last_account_info);
 }
 
 TEST_F(FeedApiTest, AllowSignedInRequestAfterHistoryIsDeletedAfterDelay) {
@@ -864,7 +859,7 @@
   WaitForIdleTaskQueue();
 
   EXPECT_EQ("loading -> [user@foo] 2 slices", surface.DescribeUpdates());
-  EXPECT_NE("", network_.last_gaia);
+  EXPECT_NE(AccountInfo{}, network_.last_account_info);
   EXPECT_TRUE(stream_->GetMetadata().session_id().token().empty());
 }
 
@@ -900,6 +895,20 @@
                        stream_->GetModel(kForYouStream)->DumpStateForTesting());
 }
 
+TEST_F(FeedApiTest, LoadStreamFromStoreValidatesUser) {
+  // Fill the store with stream data for another user.
+  {
+    auto state = MakeTypicalInitialModelState();
+    state->stream_data.set_email("other@gmail.com");
+    store_->OverwriteStream(kForYouStream, std::move(state), base::DoNothing());
+  }
+
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ("loading -> cant-refresh", surface.DescribeUpdates());
+}
+
 TEST_F(FeedApiTest, LoadingSpinnerIsSentInitially) {
   store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
                           base::DoNothing());
@@ -1209,9 +1218,8 @@
   ASSERT_EQ(absl::optional<bool>(true), callback.GetResult());
   EXPECT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates());
   // The root ID should not change for next-page content.
-  EXPECT_EQ(
-      MakeRootEventId(),
-      stream_->GetLoggingParameters(surface.GetStreamType()).root_event_id);
+  EXPECT_EQ(MakeRootEventId(),
+            surface.update->logging_parameters().root_event_id());
 }
 
 TEST_P(FeedStreamTestForAllStreamTypes, LoadMorePersistsData) {
@@ -1422,7 +1430,7 @@
             schedule.refresh_offsets);
 
   // The stream's user attributes are set, so activity logging is enabled.
-  EXPECT_TRUE(stream_->IsActivityLoggingEnabled(kForYouStream));
+  EXPECT_TRUE(surface.update->logging_parameters().logging_enabled());
   // This network response has content.
   EXPECT_TRUE(stream_->HasUnreadContent(kForYouStream));
 }
@@ -1480,21 +1488,23 @@
   EXPECT_EQ(false, cr.GetResult());
   EXPECT_EQ(
       "loading -> [user@foo] 2 slices -> 2 slices +spinner -> 2 slices -> "
-      "loading -> [NO logging user@foo] 2 slices",
+      "loading -> 2 slices",
       surface.DescribeUpdates());
 }
 
 TEST_F(FeedApiTest, ClearAllWipesAllState) {
   // Trigger saving a consistency token, so it can be cleared later.
   network_.consistency_token = "token-11";
-  stream_->UploadAction(MakeFeedAction(42ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   // Trigger saving a feed stream, so it can be cleared later.
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
   TestForYouSurface surface(stream_.get());
   WaitForIdleTaskQueue();
 
   // Enqueue an action, so it can be cleared later.
-  stream_->UploadAction(MakeFeedAction(43ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(43ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
 
   // Trigger ClearAll, this should erase everything.
   stream_->OnCacheDataCleared();
@@ -1511,11 +1521,12 @@
 )",
             DumpStoreState(true));
   EXPECT_EQ("", stream_->GetMetadata().consistency_token());
-  EXPECT_FALSE(stream_->IsActivityLoggingEnabled(kForYouStream));
+  EXPECT_FALSE(surface.update->logging_parameters().logging_enabled());
 }
 
 TEST_F(FeedApiTest, StorePendingAction) {
-  stream_->UploadAction(MakeFeedAction(42ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
 
   std::vector<feedstore::StoredAction> result =
@@ -1527,17 +1538,19 @@
 }
 
 TEST_F(FeedApiTest, UploadActionWhileSignedOutIsNoOp) {
-  signed_in_gaia_ = "";
-  ASSERT_EQ(stream_->GetSyncSignedInGaia(), "");
-  stream_->UploadAction(MakeFeedAction(42ul), false, base::DoNothing());
+  account_info_ = {};
+  ASSERT_EQ(stream_->GetAccountInfo(), AccountInfo{});
+  stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
 
   EXPECT_EQ(0ul, ReadStoredActions(stream_->GetStore()).size());
 }
 
 TEST_F(FeedApiTest, SignOutWhileUploadActionDoesNotUpload) {
-  stream_->UploadAction(MakeFeedAction(42ul), true, base::DoNothing());
-  signed_in_gaia_ = "";
+  stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
+  account_info_ = {};
 
   WaitForIdleTaskQueue();
 
@@ -1548,7 +1561,8 @@
 
 TEST_F(FeedApiTest, ClearAllWhileUploadActionDoesNotUpload) {
   CallbackReceiver<UploadActionsTask::Result> cr;
-  stream_->UploadAction(MakeFeedAction(42ul), true, cr.Bind());
+  stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), true,
+                        cr.Bind());
   stream_->OnCacheDataCleared();  // triggers ClearAll().
   WaitForIdleTaskQueue();
 
@@ -1561,9 +1575,10 @@
 
 TEST_F(FeedApiTest, WrongUserUploadActionDoesNotUpload) {
   CallbackReceiver<UploadActionsTask::Result> cr;
-  stream_->UploadAction(MakeFeedAction(42ul), true, cr.Bind());
-  // Sign in as another user.
-  signed_in_gaia_ = "someothergaia";
+  LoggingParameters logging_parameters = CreateLoggingParameters();
+  logging_parameters.email = "someothergaia";
+  stream_->UploadAction(MakeFeedAction(42ul), logging_parameters, true,
+                        cr.Bind());
 
   WaitForIdleTaskQueue();
 
@@ -1575,6 +1590,23 @@
   EXPECT_EQ(0ul, cr.GetResult()->upload_attempt_count);
 }
 
+TEST_F(FeedApiTest, LoggingPropertiesWithNoAccountDoesNotUpload) {
+  CallbackReceiver<UploadActionsTask::Result> cr;
+  LoggingParameters logging_parameters = CreateLoggingParameters();
+  logging_parameters.email.clear();
+  stream_->UploadAction(MakeFeedAction(42ul), logging_parameters, true,
+                        cr.Bind());
+
+  WaitForIdleTaskQueue();
+
+  // Action should not upload.
+  EXPECT_EQ(UploadActionsStatus::kAbortUploadForSignedOutUser,
+            metrics_reporter_->upload_action_status);
+  EXPECT_EQ(0, network_.GetActionRequestCount());
+  ASSERT_TRUE(cr.GetResult());
+  EXPECT_EQ(0ul, cr.GetResult()->upload_attempt_count);
+}
+
 TEST_F(FeedApiTest, StorePendingActionAndUploadNow) {
   network_.consistency_token = "token-11";
 
@@ -1583,7 +1615,8 @@
   {
     feedwire::ThereAndBackAgainData msg;
     *msg.mutable_action_payload() = MakeFeedAction(42ul).action_payload();
-    stream_->ProcessThereAndBackAgain(msg.SerializeAsString());
+    stream_->ProcessThereAndBackAgain(msg.SerializeAsString(),
+                                      CreateLoggingParameters());
   }
   WaitForIdleTaskQueue();
 
@@ -1597,7 +1630,8 @@
 TEST_F(FeedApiTest, ProcessViewActionResultsInDelayedUpload) {
   network_.consistency_token = "token-11";
 
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
+  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString(),
+                             CreateLoggingParameters());
   WaitForIdleTaskQueue();
   // Verify it's not uploaded immediately.
   ASSERT_EQ(0, network_.GetActionRequestCount());
@@ -1610,16 +1644,30 @@
   EXPECT_EQ(1, network_.GetActionRequestCount());
 }
 
+TEST_F(FeedApiTest, ProcessViewActionDroppedBecauseNotEnabled) {
+  network_.consistency_token = "token-11";
+  LoggingParameters logging_parameters = CreateLoggingParameters();
+  logging_parameters.view_actions_enabled = false;
+  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString(),
+                             logging_parameters);
+  WaitForIdleTaskQueue();
+  // Verify it's not uploaded, and not stored.
+  ASSERT_EQ(0, network_.GetActionRequestCount());
+  ASSERT_EQ(0ull, ReadStoredActions(stream_->GetStore()).size());
+}
+
 TEST_F(FeedApiTest, ActionsUploadWithoutConditionsWhenFeatureDisabled) {
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
 
   TestForYouSurface surface(stream_.get());
   WaitForIdleTaskQueue();
   stream_->ProcessViewAction(
-      feedwire::FeedAction::default_instance().SerializeAsString());
+      feedwire::FeedAction::default_instance().SerializeAsString(),
+      surface.GetLoggingParameters());
   WaitForIdleTaskQueue();
   stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
+      MakeThereAndBackAgainData(42ul).SerializeAsString(),
+      surface.GetLoggingParameters());
   WaitForIdleTaskQueue();
 
   // Verify the actions were uploaded.
@@ -1628,7 +1676,8 @@
 }
 
 TEST_F(FeedApiTest, LoadStreamFromNetworkUploadsActions) {
-  stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(99ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
 
   TestForYouSurface surface(stream_.get());
@@ -1638,7 +1687,8 @@
   EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
 
   // Uploaded action should have been erased from store.
-  stream_->UploadAction(MakeFeedAction(100ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(100ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
   EXPECT_EQ(2, network_.GetActionRequestCount());
   EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
@@ -1646,15 +1696,19 @@
 
 TEST_F(FeedApiTest, UploadedActionsHaveSequentialNumbers) {
   // Send 3 actions.
-  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
-  stream_->UploadAction(MakeFeedAction(2ul), false, base::DoNothing());
-  stream_->UploadAction(MakeFeedAction(3ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(2ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(3ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
   ASSERT_EQ(1, network_.GetActionRequestCount());
   feedwire::UploadActionsRequest request1 = *network_.GetActionRequestSent();
 
   // Send another action in a new request.
-  stream_->UploadAction(MakeFeedAction(4ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(4ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
   ASSERT_EQ(2, network_.GetActionRequestCount());
   feedwire::UploadActionsRequest request2 = *network_.GetActionRequestSent();
@@ -1674,7 +1728,8 @@
   TestForYouSurface surface(stream_.get());
   WaitForIdleTaskQueue();
 
-  stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(99ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
 
   network_.consistency_token = "token-12";
@@ -1687,7 +1742,8 @@
 
   // Uploaded action should have been erased from the store.
   network_.ClearTestData();
-  stream_->UploadAction(MakeFeedAction(100ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(100ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
   EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
 
@@ -1697,32 +1753,25 @@
           network_.GetActionRequestSent()->feed_actions(0).action_payload()));
 }
 
-TEST_F(FeedApiTest, LoadMoreUpdatesIsActivityLoggingEnabled) {
-  EXPECT_FALSE(stream_->IsActivityLoggingEnabled(kForYouStream));
+TEST_F(FeedApiTest, LoadMoreDoesNotUpdateLoggingEnabled) {
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
   TestForYouSurface surface(stream_.get());
   WaitForIdleTaskQueue();
-  EXPECT_TRUE(stream_->IsActivityLoggingEnabled(kForYouStream));
+  EXPECT_TRUE(surface.update->logging_parameters().logging_enabled());
 
   int page = 2;
-  for (bool signed_in : {true, false}) {
-    for (bool waa_on : {true, false}) {
-      for (bool privacy_notice_fulfilled : {true, false}) {
-        response_translator_.InjectResponse(
-            MakeTypicalNextPageState(page++, kTestTimeEpoch, signed_in, waa_on,
-                                     privacy_notice_fulfilled));
-        CallbackReceiver<bool> callback;
-        stream_->LoadMore(surface, callback.Bind());
-        WaitForIdleTaskQueue();
-        EXPECT_EQ(
-            stream_->IsActivityLoggingEnabled(kForYouStream),
-            (signed_in && waa_on) ||
-                (!signed_in && GetFeedConfig().send_signed_out_session_logs))
-            << "signed_in=" << signed_in << " waa_on=" << waa_on
-            << " privacy_notice_fulfilled=" << privacy_notice_fulfilled
-            << " send_signed_out_session_logs="
-            << GetFeedConfig().send_signed_out_session_logs;
-      }
+  // A NextPage request will not work when signed-out.
+  const bool signed_in = true;
+
+  // Logging parameters are not updated on LoadMore(), so logging remains
+  // enabled until the next refresh.
+  for (bool waa_on : {true, false}) {
+    for (bool privacy_notice_fulfilled : {true, false}) {
+      response_translator_.InjectResponse(MakeTypicalNextPageState(
+          page++, kTestTimeEpoch, signed_in, waa_on, privacy_notice_fulfilled));
+      stream_->LoadMore(surface, base::DoNothing());
+      WaitForIdleTaskQueue();
+      EXPECT_TRUE(surface.update->logging_parameters().logging_enabled());
     }
   }
 }
@@ -1731,13 +1780,14 @@
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
   TestForYouSurface surface(stream_.get());
   WaitForIdleTaskQueue();
-  EXPECT_TRUE(stream_->IsActivityLoggingEnabled(kForYouStream));
 
+  EXPECT_TRUE(surface.update->logging_parameters().logging_enabled());
   EXPECT_EQ("loading -> [user@foo] 2 slices", surface.DescribeUpdates());
 }
 
 TEST_F(FeedApiTest, BackgroundingAppUploadsActions) {
-  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
   stream_->OnEnterBackground();
   WaitForIdleTaskQueue();
   EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
@@ -1752,14 +1802,16 @@
   config.upload_actions_on_enter_background = false;
   SetFeedConfigForTesting(config);
 
-  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
   stream_->OnEnterBackground();
   WaitForIdleTaskQueue();
   EXPECT_EQ(0, network_.GetActionRequestCount());
 }
 
 TEST_F(FeedApiTest, UploadedActionsAreNotSentAgain) {
-  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
   stream_->OnEnterBackground();
   WaitForIdleTaskQueue();
   ASSERT_EQ(1, network_.GetActionRequestCount());
@@ -1777,7 +1829,8 @@
   EXPECT_EQ(1, network_.GetActionRequestCount());
   EXPECT_EQ(3, network_.GetActionRequestSent()->feed_actions_size());
 
-  stream_->UploadAction(MakeFeedAction(99ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(99ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
   EXPECT_EQ(2, network_.GetActionRequestCount());
   EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
@@ -1799,20 +1852,23 @@
 
   EXPECT_EQ(3, network_.GetActionRequestCount());
 
-  stream_->UploadAction(MakeFeedAction(99ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(99ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
   EXPECT_EQ(4, network_.GetActionRequestCount());
   EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
 }
 
 TEST_F(FeedApiTest, UploadActionsSkipsStaleActionsByTimestamp) {
-  stream_->UploadAction(MakeFeedAction(2ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(2ul), CreateLoggingParameters(), false,
+                        base::DoNothing());
   WaitForIdleTaskQueue();
   task_environment_.FastForwardBy(base::Hours(25));
 
   // Trigger upload
   CallbackReceiver<UploadActionsTask::Result> cr;
-  stream_->UploadAction(MakeFeedAction(3ul), true, cr.Bind());
+  stream_->UploadAction(MakeFeedAction(3ul), CreateLoggingParameters(), true,
+                        cr.Bind());
   WaitForIdleTaskQueue();
 
   // Just one action should have been uploaded.
@@ -1831,14 +1887,18 @@
 TEST_F(FeedApiTest, UploadActionsErasesStaleActionsByAttempts) {
   // Three failed uploads, plus one more to cause the first action to be erased.
   network_.InjectEmptyActionRequestResult();
-  stream_->UploadAction(MakeFeedAction(0ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(0ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   network_.InjectEmptyActionRequestResult();
-  stream_->UploadAction(MakeFeedAction(1ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
   network_.InjectEmptyActionRequestResult();
-  stream_->UploadAction(MakeFeedAction(2ul), true, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(2ul), CreateLoggingParameters(), true,
+                        base::DoNothing());
 
   CallbackReceiver<UploadActionsTask::Result> cr;
-  stream_->UploadAction(MakeFeedAction(3ul), true, cr.Bind());
+  stream_->UploadAction(MakeFeedAction(3ul), CreateLoggingParameters(), true,
+                        cr.Bind());
   WaitForIdleTaskQueue();
 
   // Four requests, three pending actions in the last request.
@@ -1858,7 +1918,7 @@
     feedstore::Metadata initial_metadata;
     feedstore::SetSessionId(initial_metadata, "session-id", kExpiry);
     initial_metadata.set_consistency_token("token");
-    initial_metadata.set_gaia(GetSyncSignedInGaia());
+    initial_metadata.set_gaia(GetAccountInfo().gaia);
     store_->WriteMetadata(initial_metadata, base::DoNothing());
   }
 
@@ -2016,7 +2076,7 @@
   const std::string kSessionToken1("session-token-1");
   const std::string kSessionToken2("session-token-2");
 
-  signed_in_gaia_ = "";
+  account_info_ = {};
 
   StreamModelUpdateRequestGenerator model_generator;
   model_generator.signed_in = false;
@@ -2116,7 +2176,7 @@
 }
 
 TEST_F(FeedApiTest, ClearAllResetsSessionId) {
-  signed_in_gaia_ = "";
+  account_info_ = {};
 
   // Initialize a session id.
   feedstore::Metadata metadata = stream_->GetMetadata();
@@ -2137,7 +2197,7 @@
   const std::string kSessionToken1("session-token-1");
   const std::string kSessionToken2("session-token-2");
 
-  signed_in_gaia_ = "";
+  account_info_ = {};
 
   StreamModelUpdateRequestGenerator model_generator;
   model_generator.signed_in = false;
@@ -2206,7 +2266,7 @@
 
   StreamModelUpdateRequestGenerator model_generator;
   model_generator.signed_in = false;
-  signed_in_gaia_ = "";
+  account_info_ = {};
 
   // (1) Do an initial load of the store
   //     - this should trigger a network request
@@ -2788,7 +2848,7 @@
 
 // This is a regression test for crbug.com/1249772.
 TEST_F(FeedApiTest, SignInWhileSurfaceIsOpen) {
-  signed_in_gaia_.clear();  // not signed in initially.
+  account_info_ = {};  // not signed in initially.
   // Load content and simulate a restart, so that there is stored content.
   {
     response_translator_.InjectResponse(MakeTypicalInitialModelState());
@@ -2803,7 +2863,7 @@
   stream_->ReportFeedViewed(surface.GetStreamType(), surface.GetSurfaceId());
   TestUnreadContentObserver observer;
   stream_->AddUnreadContentObserver(kForYouStream, &observer);
-  signed_in_gaia_ = "gaia";
+  account_info_ = TestAccountInfo();
   stream_->OnSignedIn();
   response_translator_.InjectResponse(MakeTypicalRefreshModelState());
   WaitForIdleTaskQueue();
@@ -2819,7 +2879,7 @@
   response_translator_.InjectResponse(MakeTypicalInitialModelState());
   TestForYouSurface surface(stream_.get());
   WaitForIdleTaskQueue();
-  signed_in_gaia_ = "";
+  account_info_ = {};
   stream_->OnSignedOut();
   response_translator_.InjectResponse(MakeTypicalRefreshModelState());
   WaitForIdleTaskQueue();
diff --git a/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc b/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
index f1dbd1c..469d01b 100644
--- a/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
@@ -23,6 +23,10 @@
 namespace {
 using testing::PrintToString;
 
+AccountInfo TestAccountInfo() {
+  return {"examplegaia", "example@foo.com"};
+}
+
 FeedNetwork::RawResponse MakeFailedResponse() {
   FeedNetwork::RawResponse network_response;
   network_response.response_info.status_code = 400;
@@ -733,7 +737,7 @@
   }
 
   // Sign out, and verify recommended web feeds are cleared.
-  signed_in_gaia_ = "";
+  account_info_ = {};
   stream_->OnSignedOut();
   WaitForIdleTaskQueue();
   ASSERT_EQ(1, network_.GetListRecommendedWebFeedsRequestCount());
@@ -753,12 +757,12 @@
   ASSERT_EQ(1, network_.GetListRecommendedWebFeedsRequestCount());
 
   // Sign out, this clears recommended Web Feeds.
-  signed_in_gaia_ = "";
+  account_info_ = {};
   stream_->OnSignedOut();
   WaitForIdleTaskQueue();
 
   // Sign in, and verify web feeds are fetched and stored.
-  signed_in_gaia_ = "examplegaia";
+  account_info_ = TestAccountInfo();
   stream_->OnSignedIn();
   WaitForIdleTaskQueue();
 
@@ -875,7 +879,7 @@
   }
 
   // Sign out, and verify recommended web feeds are cleared.
-  signed_in_gaia_ = "";
+  account_info_ = {};
   stream_->OnSignedOut();
   WaitForIdleTaskQueue();
   ASSERT_EQ(1, network_.GetListFollowedWebFeedsRequestCount());
@@ -895,14 +899,14 @@
   ASSERT_EQ(1, network_.GetListFollowedWebFeedsRequestCount());
 
   // Sign out, and verify no web feeds are fetched.
-  signed_in_gaia_ = "";
+  account_info_ = {};
   stream_->OnSignedOut();
   WaitForIdleTaskQueue();
   ASSERT_EQ(1, network_.GetListFollowedWebFeedsRequestCount());
   EXPECT_EQ("{}", PrintToString(CheckAllSubscriptions()));
 
   // Sign in, and verify web feeds are fetched and stored.
-  signed_in_gaia_ = "examplegaia";
+  account_info_ = TestAccountInfo();
   stream_->OnSignedIn();
   WaitForIdleTaskQueue();
 
diff --git a/components/feed/core/v2/api_test/feed_api_test.cc b/components/feed/core/v2/api_test/feed_api_test.cc
index 2c9a542..9d23dcf2 100644
--- a/components/feed/core/v2/api_test/feed_api_test.cc
+++ b/components/feed/core/v2/api_test/feed_api_test.cc
@@ -8,7 +8,9 @@
 #include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
 #include "components/feed/core/v2/enums.h"
 #include "components/feed/core/v2/feed_network.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
 #include "components/feed/core/v2/public/reliability_logging_bridge.h"
+#include "components/feed/core/v2/types.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 
 #include "base/callback.h"
@@ -50,7 +52,8 @@
   std::unique_ptr<StreamModelUpdateRequest> data =
       StoredModelData(stream_type, store);
   if (data) {
-    auto model = std::make_unique<StreamModel>(context);
+    auto model = std::make_unique<StreamModel>(
+        context, MakeLoggingParameters("client-instance", *data));
     model->Update(std::move(data));
     return model;
   }
@@ -67,8 +70,9 @@
   LoadStreamFromStoreTask load_task(
       LoadStreamFromStoreTask::LoadType::kFullLoad, nullptr, stream_type, store,
       /*missed_last_refresh=*/false, base::BindLambdaForTesting(complete));
-  // We want to load the data no matter how stale.
+  // We want to load the data no matter how stale, or which account.
   load_task.IgnoreStalenessForTesting();
+  load_task.IngoreAccountForTesting();
 
   base::RunLoop run_loop;
   load_task.Execute(run_loop.QuitClosure());
@@ -86,7 +90,7 @@
     std::vector<feedstore::DataOperation> operations,
     std::vector<feedstore::DataOperation> more_operations) {
   StreamModel::Context context;
-  StreamModel model(&context);
+  StreamModel model(&context, LoggingParameters{});
   model.Update(std::move(update_request));
   model.ExecuteOperations(operations);
   model.ExecuteOperations(more_operations);
@@ -212,6 +216,11 @@
     const {
   return data_store_entries_;
 }
+LoggingParameters TestSurfaceBase::GetLoggingParameters() const {
+  if (update)
+    return FromProto(update->logging_parameters());
+  return {};
+}
 std::string TestSurfaceBase::CurrentState() {
   if (update && IsInitialLoadSpinnerUpdate(*update))
     return "loading";
@@ -230,6 +239,7 @@
     if (update->logging_parameters().logging_enabled()) {
       // View actions will always be enabled if logging is enabled.
       CHECK(update->logging_parameters().view_actions_enabled());
+      CHECK_NE("", update->logging_parameters().email());
       logging_parameters_description = update->logging_parameters().email();
     } else if (!update->logging_parameters().email().empty()) {
       if (update->logging_parameters().view_actions_enabled()) {
@@ -405,9 +415,9 @@
 void TestFeedNetwork::SendQueryRequest(
     NetworkRequestType request_type,
     const feedwire::Request& request,
-    const std::string& gaia,
+    const AccountInfo& account_info,
     base::OnceCallback<void(QueryRequestResult)> callback) {
-  last_gaia = gaia;
+  last_account_info = account_info;
   ++send_query_call_count;
   // Emulate a successful response.
   // The response body is currently an empty message, because most of the
@@ -422,7 +432,7 @@
 
   result.response_info.response_body_bytes = 100;
   result.response_info.fetch_duration = base::Milliseconds(42);
-  result.response_info.was_signed_in = true;
+  result.response_info.account_info = account_info;
   if (injected_response_) {
     result.response_body = std::make_unique<feedwire::Response>(
         std::move(injected_response_.value()));
@@ -467,9 +477,9 @@
     base::StringPiece api_path,
     base::StringPiece method,
     std::string request_bytes,
-    const std::string& gaia,
+    const AccountInfo& account_info,
     base::OnceCallback<void(RawResponse)> callback) {
-  last_gaia = gaia;
+  last_account_info = account_info;
   api_requests_sent_[request_type] = request_bytes;
   ++api_request_count_[request_type];
   std::vector<RawResponse>& injected_responses =
@@ -656,17 +666,29 @@
 RefreshResponseData TestWireResponseTranslator::TranslateWireResponse(
     feedwire::Response response,
     StreamModelUpdateRequest::Source source,
-    bool was_signed_in_request,
+    const AccountInfo& account_info,
     base::Time current_time) const {
   if (!injected_responses_.empty()) {
     if (injected_responses_[0].model_update_request)
       injected_responses_[0].model_update_request->source = source;
     RefreshResponseData result = std::move(injected_responses_[0]);
     injected_responses_.erase(injected_responses_.begin());
+    // Update the injected response so that it matches the account info.
+    if (result.model_update_request) {
+      if (account_info.IsEmpty()) {
+        result.model_update_request->stream_data.set_signed_in(false);
+        result.model_update_request->stream_data.clear_gaia();
+        result.model_update_request->stream_data.clear_email();
+      } else {
+        result.model_update_request->stream_data.set_signed_in(true);
+        result.model_update_request->stream_data.set_gaia(account_info.gaia);
+        result.model_update_request->stream_data.set_email(account_info.email);
+      }
+    }
     return result;
   }
   return WireResponseTranslator::TranslateWireResponse(
-      std::move(response), source, was_signed_in_request, current_time);
+      std::move(response), source, account_info, current_time);
 }
 void TestWireResponseTranslator::InjectResponse(
     std::unique_ptr<StreamModelUpdateRequest> response,
@@ -825,11 +847,8 @@
 bool FeedApiTest::IsOffline() {
   return is_offline_;
 }
-std::string FeedApiTest::GetSyncSignedInGaia() {
-  return signed_in_gaia_;
-}
-std::string FeedApiTest::GetSyncSignedInEmail() {
-  return signed_in_gaia_.empty() ? "" : signed_in_email_;
+AccountInfo FeedApiTest::GetAccountInfo() {
+  return account_info_;
 }
 void FeedApiTest::RegisterFollowingFeedFollowCountFieldTrial(
     size_t follow_count) {
@@ -875,7 +894,8 @@
 }
 
 std::unique_ptr<StreamModel> FeedApiTest::CreateStreamModel() {
-  return std::make_unique<StreamModel>(&stream_model_context_);
+  return std::make_unique<StreamModel>(&stream_model_context_,
+                                       LoggingParameters{});
 }
 
 bool FeedApiTest::IsTaskQueueIdle() const {
@@ -926,12 +946,19 @@
   EXPECT_EQ(WebFeedSubscriptionRequestStatus::kSuccess,
             callback.RunAndGetResult().request_status);
 }
-
+LoggingParameters FeedApiTest::CreateLoggingParameters() {
+  LoggingParameters result;
+  result.logging_enabled = true;
+  result.view_actions_enabled = true;
+  result.client_instance_id = "instance1";
+  result.email = account_info_.email;
+  return result;
+}
 void FeedApiTest::UploadActions(std::vector<feedwire::FeedAction> actions) {
   size_t actions_remaining = actions.size();
   for (feedwire::FeedAction& action : actions) {
-    stream_->UploadAction(action, (--actions_remaining) == 0ul,
-                          base::DoNothing());
+    stream_->UploadAction(action, CreateLoggingParameters(),
+                          (--actions_remaining) == 0ul, base::DoNothing());
   }
 }
 
diff --git a/components/feed/core/v2/api_test/feed_api_test.h b/components/feed/core/v2/api_test/feed_api_test.h
index a0cef99..de58e880 100644
--- a/components/feed/core/v2/api_test/feed_api_test.h
+++ b/components/feed/core/v2/api_test/feed_api_test.h
@@ -140,6 +140,8 @@
   std::string DescribeState();
 
   std::map<std::string, std::string> GetDataStoreEntries() const;
+  // Returns the logging parameters last sent to the surface.
+  LoggingParameters GetLoggingParameters() const;
 
   // The initial state of the stream, if it was received. This is nullopt if
   // only the loading spinner was seen.
@@ -200,7 +202,7 @@
   void SendQueryRequest(
       NetworkRequestType request_type,
       const feedwire::Request& request,
-      const std::string& gaia,
+      const AccountInfo& account_info,
       base::OnceCallback<void(QueryRequestResult)> callback) override;
 
   void SendDiscoverApiRequest(
@@ -208,7 +210,7 @@
       base::StringPiece api_path,
       base::StringPiece method,
       std::string request_bytes,
-      const std::string& gaia,
+      const AccountInfo& account_info,
       base::OnceCallback<void(RawResponse)> callback) override;
 
   void CancelRequests() override;
@@ -227,6 +229,7 @@
     response.response_info.status_code = 200;
     response.response_bytes = response_message.SerializeAsString();
     response.response_info.response_body_bytes = response.response_bytes.size();
+    response.response_info.account_info = last_account_info;
     InjectApiRawResponse<API>(std::move(response));
   }
 
@@ -314,7 +317,7 @@
   absl::optional<feedwire::Request> query_request_sent;
   // Number of FeedQuery requests sent (including Web Feed ListContents).
   int send_query_call_count = 0;
-  std::string last_gaia;
+  AccountInfo last_account_info;
   // The consistency token to use when constructing default network responses.
   std::string consistency_token;
   bool forced_signed_out_request = false;
@@ -343,7 +346,7 @@
   RefreshResponseData TranslateWireResponse(
       feedwire::Response response,
       StreamModelUpdateRequest::Source source,
-      bool was_signed_in_request,
+      const AccountInfo& account_info,
       base::Time current_time) const override;
   void InjectResponse(std::unique_ptr<StreamModelUpdateRequest> response,
                       absl::optional<std::string> session_id = absl::nullopt);
@@ -439,8 +442,7 @@
   std::string GetLanguageTag() override;
   bool IsAutoplayEnabled() override;
   void ClearAll() override;
-  std::string GetSyncSignedInGaia() override;
-  std::string GetSyncSignedInEmail() override;
+  AccountInfo GetAccountInfo() override;
   void PrefetchImage(const GURL& url) override;
   void RegisterExperiments(const Experiments& experiments) override {}
   void RegisterFollowingFeedFollowCountFieldTrial(size_t follow_count) override;
@@ -460,6 +462,9 @@
   std::string DumpStoreState(bool print_keys = false);
 
   void UploadActions(std::vector<feedwire::FeedAction> actions);
+  // Returns some logging parameters for the current signed in user. Prefer to
+  // use the logging parameters passed to TestSurface*.
+  LoggingParameters CreateLoggingParameters();
 
  protected:
   base::test::TaskEnvironment task_environment_{
@@ -490,8 +495,7 @@
   std::unique_ptr<FeedStream> stream_;
   bool is_eula_accepted_ = true;
   bool is_offline_ = false;
-  std::string signed_in_gaia_ = "examplegaia";
-  std::string signed_in_email_ = "user@foo";
+  AccountInfo account_info_ = TestAccountInfo();
   int prefetch_image_call_count_ = 0;
   std::vector<GURL> prefetched_images_;
   base::RepeatingClosure on_clear_all_;
diff --git a/components/feed/core/v2/enums.h b/components/feed/core/v2/enums.h
index 73c5cd3..0c99fe0f 100644
--- a/components/feed/core/v2/enums.h
+++ b/components/feed/core/v2/enums.h
@@ -100,6 +100,7 @@
   kUpdatedConsistencyToken = 4,
   kFinishedWithoutUpdatingConsistencyToken = 5,
   kAbortUploadForSignedOutUser = 6,
+  // TODO(b/213622639): This is unused, remove it.
   kAbortUploadBecauseDisabled = 7,
   kAbortUploadForWrongUser = 8,
   kAbortUploadActionsWithPendingClearAll = 9,
diff --git a/components/feed/core/v2/feed_network.h b/components/feed/core/v2/feed_network.h
index 489de1f..6f1ef8d 100644
--- a/components/feed/core/v2/feed_network.h
+++ b/components/feed/core/v2/feed_network.h
@@ -24,6 +24,7 @@
 }  // namespace feedwire
 
 namespace feed {
+struct AccountInfo;
 
 // DiscoverApi types. Defines information about each discover API. For use with
 // `FeedNetwork::SendApiRequest()`.
@@ -164,7 +165,7 @@
   virtual void SendQueryRequest(
       NetworkRequestType request_type,
       const feedwire::Request& request,
-      const std::string& gaia,
+      const AccountInfo& account_info,
       base::OnceCallback<void(QueryRequestResult)> callback) = 0;
 
   // Send a Discover API request. Usage:
@@ -172,13 +173,13 @@
   template <typename API>
   void SendApiRequest(
       const typename API::Request& request,
-      const std::string& gaia,
+      const AccountInfo& account_info,
       base::OnceCallback<void(ApiResult<typename API::Response>)> callback) {
     std::string binary_proto;
     request.SerializeToString(&binary_proto);
     SendDiscoverApiRequest(
         API::kRequestType, API::RequestPath(request), API::Method(),
-        std::move(binary_proto), gaia,
+        std::move(binary_proto), account_info,
         base::BindOnce(&ParseAndForwardApiResponse<API>, std::move(callback)));
   }
 
@@ -195,7 +196,7 @@
       base::StringPiece api_path,
       base::StringPiece method,
       std::string request_bytes,
-      const std::string& gaia,
+      const AccountInfo& account_info,
       base::OnceCallback<void(RawResponse)> callback) = 0;
 
   template <typename API>
diff --git a/components/feed/core/v2/feed_network_impl.cc b/components/feed/core/v2/feed_network_impl.cc
index 87458053..2545103f 100644
--- a/components/feed/core/v2/feed_network_impl.cc
+++ b/components/feed/core/v2/feed_network_impl.cc
@@ -162,7 +162,7 @@
                signin::IdentityManager* identity_manager,
                network::SharedURLLoaderFactory* loader_factory,
                const std::string& api_key,
-               const std::string& gaia,
+               const AccountInfo& account_info,
                bool allow_bless_auth)
       : url_(url),
         request_method_(request_method),
@@ -172,7 +172,7 @@
         loader_factory_(loader_factory),
         api_key_(api_key),
         entire_send_start_ticks_(base::TimeTicks::Now()),
-        gaia_(gaia),
+        account_info_(account_info),
         allow_bless_auth_(allow_bless_auth) {}
   ~NetworkFetch() = default;
   NetworkFetch(const NetworkFetch&) = delete;
@@ -181,7 +181,7 @@
   void Start(base::OnceCallback<void(RawResponse)> done_callback) {
     done_callback_ = std::move(done_callback);
 
-    if (gaia_.empty()) {
+    if (account_info_.IsEmpty()) {
       StartLoader();
       return;
     }
@@ -203,7 +203,7 @@
   void AccessTokenFetchFinished(base::TimeTicks token_start_ticks,
                                 GoogleServiceAuthError error,
                                 signin::AccessTokenInfo access_token_info) {
-    DCHECK(!gaia_.empty());
+    DCHECK(!account_info_.IsEmpty());
     UMA_HISTOGRAM_ENUMERATION(
         "ContentSuggestions.Feed.Network.TokenFetchStatus", error.state(),
         GoogleServiceAuthError::NUM_STATES);
@@ -215,7 +215,7 @@
     access_token_ = access_token_info.token;
 
     // Abort if the signed-in user doesn't match.
-    if (delegate_->GetSyncSignedInGaia() != gaia_) {
+    if (delegate_->GetAccountInfo() != account_info_) {
       NetworkResponseInfo response_info;
       RawResponse raw_response;
       response_info.status_code = net::ERR_INVALID_ARGUMENT;
@@ -346,7 +346,9 @@
         base::TimeTicks::Now() - entire_send_start_ticks_;
     response_info.fetch_time = base::Time::Now();
     response_info.base_request_url = GetUrlWithoutQuery(url_);
-    response_info.was_signed_in = !access_token_.empty();
+    if (!access_token_.empty()) {
+      response_info.account_info = account_info_;
+    }
     response_info.loader_start_time_ticks = loader_only_start_ticks_;
     response_info.encoded_size_bytes =
         completion_status ? completion_status->encoded_data_length : 0;
@@ -424,7 +426,7 @@
   // Set when the NetworkFetch is constructed, before token and article fetch.
   const base::TimeTicks entire_send_start_ticks_;
 
-  const std::string gaia_;
+  const AccountInfo account_info_;
 
   // Should be set right before the article fetch, and after the token fetch if
   // there is one.
@@ -449,7 +451,7 @@
 void FeedNetworkImpl::SendQueryRequest(
     NetworkRequestType request_type,
     const feedwire::Request& request,
-    const std::string& gaia,
+    const AccountInfo& account_info,
     base::OnceCallback<void(QueryRequestResult)> callback) {
   std::string binary_proto;
   request.SerializeToString(&binary_proto);
@@ -496,7 +498,7 @@
   AddMothershipPayloadQueryParams(base64proto, delegate_->GetLanguageTag(),
                                   url);
   Send(url, "GET", /*request_body=*/{},
-       /*allow_bless_auth=*/host_overridden, gaia,
+       /*allow_bless_auth=*/host_overridden, account_info,
        base::BindOnce(&ParseAndForwardQueryResponse, request_type,
                       std::move(callback)));
 }
@@ -509,11 +511,11 @@
                            base::StringPiece request_method,
                            std::string request_body,
                            bool allow_bless_auth,
-                           const std::string& gaia,
+                           const AccountInfo& account_info,
                            base::OnceCallback<void(RawResponse)> callback) {
   auto fetch = std::make_unique<NetworkFetch>(
       url, request_method, std::move(request_body), delegate_,
-      identity_manager_, loader_factory_.get(), api_key_, gaia,
+      identity_manager_, loader_factory_.get(), api_key_, account_info,
       allow_bless_auth);
   NetworkFetch* fetch_unowned = fetch.get();
   pending_requests_.emplace(std::move(fetch));
@@ -530,7 +532,7 @@
     base::StringPiece request_path,
     base::StringPiece method,
     std::string request_body,
-    const std::string& gaia,
+    const AccountInfo& account_info,
     base::OnceCallback<void(RawResponse)> callback) {
   GURL url(base::StrCat({kDiscoverHost, request_path}));
   // Override url if requested.
@@ -544,7 +546,7 @@
   }
 
   Send(url, method, std::move(request_body),
-       /*allow_bless_auth=*/false, gaia, std::move(callback));
+       /*allow_bless_auth=*/false, account_info, std::move(callback));
 }
 
 void FeedNetworkImpl::SendComplete(
diff --git a/components/feed/core/v2/feed_network_impl.h b/components/feed/core/v2/feed_network_impl.h
index 917e363..3a1920b 100644
--- a/components/feed/core/v2/feed_network_impl.h
+++ b/components/feed/core/v2/feed_network_impl.h
@@ -15,6 +15,7 @@
 #include "base/strings/string_piece.h"
 #include "components/feed/core/v2/enums.h"
 #include "components/feed/core/v2/feed_network.h"
+#include "components/feed/core/v2/types.h"
 #include "components/version_info/channel.h"
 #include "url/gurl.h"
 
@@ -37,9 +38,9 @@
     // Returns a string which represents the top locale and region of the
     // device.
     virtual std::string GetLanguageTag() = 0;
-    // Returns the GAIA string for the signed in user if they are sync-enabled,
-    // or the empty string otherwise.
-    virtual std::string GetSyncSignedInGaia() = 0;
+    // Returns the AccountInfo for the signed in user if they are sync-enabled,
+    // or empty otherwise.
+    virtual AccountInfo GetAccountInfo() = 0;
   };
 
   FeedNetworkImpl(Delegate* delegate,
@@ -56,7 +57,7 @@
   void SendQueryRequest(
       NetworkRequestType request_type,
       const feedwire::Request& request,
-      const std::string& gaia,
+      const AccountInfo& account_info,
       base::OnceCallback<void(QueryRequestResult)> callback) override;
 
   void SendDiscoverApiRequest(
@@ -64,7 +65,7 @@
       base::StringPiece api_path,
       base::StringPiece method,
       std::string request_bytes,
-      const std::string& gaia,
+      const AccountInfo& account_info,
       base::OnceCallback<void(RawResponse)> callback) override;
 
   // Cancels all pending requests immediately. This could be used, for example,
@@ -80,7 +81,7 @@
             base::StringPiece request_method,
             std::string request_body,
             bool allow_bless_auth,
-            const std::string& gaia,
+            const AccountInfo& account_info,
             base::OnceCallback<void(FeedNetworkImpl::RawResponse)> callback);
 
   void SendComplete(NetworkFetch* fetch,
diff --git a/components/feed/core/v2/feed_network_impl_unittest.cc b/components/feed/core/v2/feed_network_impl_unittest.cc
index 1cf2fb67..8f654d9 100644
--- a/components/feed/core/v2/feed_network_impl_unittest.cc
+++ b/components/feed/core/v2/feed_network_impl_unittest.cc
@@ -22,6 +22,7 @@
 #include "components/feed/core/proto/v2/wire/upload_actions_request.pb.h"
 #include "components/feed/core/proto/v2/wire/upload_actions_response.pb.h"
 #include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
+#include "components/feed/core/v2/public/types.h"
 #include "components/feed/core/v2/test/callback_receiver.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
@@ -79,10 +80,10 @@
       : identity_test_env_(identity_test_env) {}
 
   std::string GetLanguageTag() override { return "en"; }
-  std::string GetSyncSignedInGaia() override {
-    return identity_test_env_->identity_manager()
-        ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
-        .gaia;
+  AccountInfo GetAccountInfo() override {
+    return AccountInfo{
+        identity_test_env_->identity_manager()->GetPrimaryAccountInfo(
+            signin::ConsentLevel::kSync)};
   }
 
   raw_ptr<signin::IdentityTestEnvironment> identity_test_env_;
@@ -116,7 +117,7 @@
     return &identity_test_env_;
   }
 
-  std::string gaia() { return delegate_.GetSyncSignedInGaia(); }
+  AccountInfo account_info() { return delegate_.GetAccountInfo(); }
 
   network::TestURLLoaderFactory* test_factory() { return &test_factory_; }
 
@@ -226,7 +227,7 @@
 TEST_F(FeedNetworkTest, SendQueryRequestEmpty) {
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   feedwire::Request(), gaia(),
+                                   feedwire::Request(), account_info(),
                                    receiver.Bind());
 
   ASSERT_TRUE(receiver.GetResult());
@@ -238,7 +239,7 @@
 TEST_F(FeedNetworkTest, SendQueryRequestSendsValidRequest) {
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   network::ResourceRequest resource_request =
       RespondToQueryRequest("", net::HTTP_OK);
@@ -260,7 +261,7 @@
 TEST_F(FeedNetworkTest, SendQueryRequestForceSignedOut) {
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), /*gaia=*/"",
+                                   GetTestFeedRequest(), AccountInfo{},
                                    receiver.Bind());
   network::ResourceRequest resource_request =
       RespondToQueryRequest("", net::HTTP_OK);
@@ -269,13 +270,15 @@
       "https://www.google.com/httpservice/retry/TrellisClankService/"
       "FeedQuery?reqpld=CAHCPgQSAggB&fmt=bin&hl=en&key=dummy_api_key",
       resource_request.url);
+  EXPECT_EQ(AccountInfo{},
+            receiver.RunAndGetResult().response_info.account_info);
   EXPECT_FALSE(resource_request.headers.HasHeader("Authorization"));
 }
 
 TEST_F(FeedNetworkTest, SendQueryRequestInvalidResponse) {
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   RespondToQueryRequest("invalid", net::HTTP_OK);
 
@@ -288,7 +291,7 @@
 TEST_F(FeedNetworkTest, SendQueryRequestReceivesResponse) {
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_OK);
 
@@ -299,7 +302,7 @@
       "https://www.google.com/httpservice/retry/TrellisClankService/FeedQuery",
       result.response_info.base_request_url);
   EXPECT_NE(base::Time(), result.response_info.fetch_time);
-  EXPECT_TRUE(result.response_info.was_signed_in);
+  EXPECT_EQ(account_info(), result.response_info.account_info);
   EXPECT_EQ(GetTestFeedResponse().response_version(),
             result.response_body->response_version());
 }
@@ -307,7 +310,7 @@
 TEST_F(FeedNetworkTest, SendQueryRequestIgnoresBodyForNon200Response) {
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_FORBIDDEN);
 
@@ -322,9 +325,9 @@
 
 TEST_F(FeedNetworkTest, SendQueryRequestFailsForWrongUser) {
   CallbackReceiver<QueryRequestResult> receiver;
-  feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), "some_other_gaia",
-                                   receiver.Bind());
+  feed_network()->SendQueryRequest(
+      NetworkRequestType::kFeedQuery, GetTestFeedRequest(),
+      {"other-gaia", "other@foo.com"}, receiver.Bind());
   task_environment_.RunUntilIdle();
   network::TestURLLoaderFactory::PendingRequest* pending_request =
       test_factory()->GetPendingRequest(0);
@@ -342,7 +345,7 @@
 TEST_F(FeedNetworkTest, CancelRequest) {
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   feed_network()->CancelRequests();
   task_environment_.FastForwardUntilNoTasksRemain();
@@ -354,7 +357,7 @@
   base::HistogramTester histogram_tester;
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   task_environment_.FastForwardBy(base::Seconds(30));
 
@@ -368,13 +371,13 @@
 TEST_F(FeedNetworkTest, ParallelRequests) {
   CallbackReceiver<QueryRequestResult> receiver1, receiver2;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver1.Bind());
   // Make another request with a different URL so Respond() won't affect both
   // requests.
   feed_network()->SendQueryRequest(
       NetworkRequestType::kFeedQuery,
-      GetTestFeedRequest(feedwire::FeedQuery::NEXT_PAGE_SCROLL), gaia(),
+      GetTestFeedRequest(feedwire::FeedQuery::NEXT_PAGE_SCROLL), account_info(),
       receiver2.Bind());
 
   // Respond to both requests, avoiding FastForwardUntilNoTasksRemain until
@@ -398,7 +401,7 @@
   CallbackReceiver<QueryRequestResult> receiver;
   base::HistogramTester histogram_tester;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_FORBIDDEN);
 
@@ -414,7 +417,7 @@
   base::HistogramTester histogram_tester;
 
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
       GoogleServiceAuthError(
@@ -441,7 +444,7 @@
   identity_env()->ClearPrimaryAccount();
   CallbackReceiver<QueryRequestResult> receiver;
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
 
   network::ResourceRequest resource_request =
@@ -458,7 +461,7 @@
   const base::TimeDelta kDuration = base::Milliseconds(12345);
 
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
   task_environment_.FastForwardBy(kDuration);
   RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_OK);
@@ -475,7 +478,7 @@
   profile_prefs().SetString(feed::prefs::kHostOverrideHost,
                             "http://www.newhost.com/");
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
 
   ASSERT_EQ("www.newhost.com", GetPendingRequestURL().host());
@@ -496,7 +499,7 @@
   profile_prefs().SetString(feed::prefs::kHostOverrideHost,
                             "http://www.newhost.com/testpath");
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
 
   ASSERT_EQ("www.newhost.com", GetPendingRequestURL().host());
@@ -509,7 +512,7 @@
   profile_prefs().SetString(feed::prefs::kHostOverrideHost,
                             "http://www.newhost.com/testpath/");
   feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
-                                   GetTestFeedRequest(), gaia(),
+                                   GetTestFeedRequest(), account_info(),
                                    receiver.Bind());
 
   ASSERT_EQ("www.newhost.com", GetPendingRequestURL().host());
@@ -521,7 +524,7 @@
   CallbackReceiver<FeedNetwork::ApiResult<feedwire::UploadActionsResponse>>
       receiver;
   feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
-      GetTestActionRequest(), gaia(), receiver.Bind());
+      GetTestActionRequest(), account_info(), receiver.Bind());
   RespondToActionRequest(GetTestActionResponse(), net::HTTP_OK);
 
   ASSERT_TRUE(receiver.GetResult());
@@ -536,8 +539,11 @@
 TEST_F(FeedNetworkTest, SendApiRequest_UploadActionsFailsForWrongUser) {
   CallbackReceiver<FeedNetwork::ApiResult<feedwire::UploadActionsResponse>>
       receiver;
+  AccountInfo other_account;
+  other_account.gaia = "some_other_gaia";
+  other_account.email = "some@other.com";
   feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
-      GetTestActionRequest(), "some_other_gaia", receiver.Bind());
+      GetTestActionRequest(), other_account, receiver.Bind());
   task_environment_.RunUntilIdle();
   network::TestURLLoaderFactory::PendingRequest* pending_request =
       test_factory()->GetPendingRequest(0);
@@ -557,7 +563,7 @@
   CallbackReceiver<FeedNetwork::ApiResult<feedwire::UploadActionsResponse>>
       receiver;
   feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
-      GetTestActionRequest(), gaia(), receiver.Bind());
+      GetTestActionRequest(), account_info(), receiver.Bind());
   network::ResourceRequest resource_request =
       RespondToActionRequest(GetTestActionResponse(), net::HTTP_OK);
 
@@ -593,7 +599,7 @@
   CallbackReceiver<
       FeedNetwork::ApiResult<feedwire::webfeed::UnfollowWebFeedResponse>>
       receiver;
-  feed_network()->SendApiRequest<UnfollowWebFeedDiscoverApi>({}, gaia(),
+  feed_network()->SendApiRequest<UnfollowWebFeedDiscoverApi>({}, account_info(),
                                                              receiver.Bind());
   RespondToDiscoverRequest("", net::HTTP_OK);
 
@@ -607,7 +613,7 @@
 }
 
 TEST_F(FeedNetworkTest, SendApiRequest_ListWebFeedsSendsCorrectContentType) {
-  feed_network()->SendApiRequest<ListWebFeedsDiscoverApi>({}, gaia(),
+  feed_network()->SendApiRequest<ListWebFeedsDiscoverApi>({}, account_info(),
                                                           base::DoNothing());
   std::string requested_content_type;
   RespondToDiscoverRequest("", net::HTTP_OK)
@@ -620,7 +626,7 @@
   profile_prefs().SetString(feed::prefs::kHostOverrideHost,
                             "http://www.newhost.com/");
   feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
-      GetTestActionRequest(), gaia(), base::DoNothing());
+      GetTestActionRequest(), account_info(), base::DoNothing());
 
   EXPECT_EQ(GURL("https://discover-pa.googleapis.com/v1/actions:upload"),
             GetPendingRequestURL());
@@ -630,7 +636,7 @@
   profile_prefs().SetString(feed::prefs::kDiscoverAPIEndpointOverride,
                             "http://www.newhost.com/");
   feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
-      GetTestActionRequest(), gaia(), base::DoNothing());
+      GetTestActionRequest(), account_info(), base::DoNothing());
 
   EXPECT_EQ(GURL("http://www.newhost.com/v1/actions:upload"),
             GetPendingRequestURL());
diff --git a/components/feed/core/v2/feed_stream.cc b/components/feed/core/v2/feed_stream.cc
index f9b4485..133cc522 100644
--- a/components/feed/core/v2/feed_stream.cc
+++ b/components/feed/core/v2/feed_stream.cc
@@ -35,6 +35,7 @@
 #include "components/feed/core/v2/protocol_translator.h"
 #include "components/feed/core/v2/public/feed_api.h"
 #include "components/feed/core/v2/public/feed_stream_surface.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
 #include "components/feed/core/v2/public/refresh_task_scheduler.h"
 #include "components/feed/core/v2/public/reliability_logging_bridge.h"
 #include "components/feed/core/v2/public/stream_type.h"
@@ -132,7 +133,6 @@
       chrome_info_(chrome_info),
       task_queue_(this),
       request_throttler_(profile_prefs),
-      upload_criteria_(profile_prefs),
       privacy_notice_card_tracker_(profile_prefs) {
   DCHECK(persistent_key_value_store_);
   DCHECK(feed_network_);
@@ -259,16 +259,12 @@
   if (result.load_type == LoadType::kManualRefresh)
     UnloadModel(result.stream_type);
 
-  // TODO(crbug.com/1268575): SetLastFetchHadNoticeCard is duplicated here to
-  // ensure that the pref is updated before LoadModel(), which needs this
-  // information. This is fragile, we should instead store this information
-  // along with the stream.
-  if (result.fetched_content_has_notice_card.has_value())
-    feed::prefs::SetLastFetchHadNoticeCard(
-        *profile_prefs_, *result.fetched_content_has_notice_card);
-
   if (result.update_request) {
-    auto model = std::make_unique<StreamModel>(&stream_model_context_);
+    auto model = std::make_unique<StreamModel>(
+        &stream_model_context_,
+        feed::MakeLoggingParameters(prefs::GetClientInstanceId(*profile_prefs_),
+
+                                    *result.update_request));
     model->Update(std::move(result.update_request));
 
     if (!model->HasVisibleContent() &&
@@ -295,7 +291,6 @@
       content_stats, GetRequestMetadata(stream.type, false),
       std::move(result.latencies));
 
-  UpdateIsActivityLoggingEnabled(result.stream_type);
   stream.model_loading_in_progress = false;
   stream.surface_updater->LoadStreamComplete(
       stream.model != nullptr, result.final_status, result.launch_result);
@@ -329,23 +324,6 @@
   }
 }
 
-LoggingParameters FeedStream::GetLoggingParameters(
-    const StreamType& stream_type) {
-  LoggingParameters logging_params;
-  logging_params.client_instance_id = GetClientInstanceId();
-  logging_params.logging_enabled = IsActivityLoggingEnabled(stream_type);
-  Stream& stream = GetStream(stream_type);
-  if (stream.model) {
-    logging_params.root_event_id = stream.model->GetRootEventId();
-  }
-  logging_params.view_actions_enabled = CanLogViews();
-  // We provide account name even if logging is disabled, so that account name
-  // can be verified for action uploads.
-  logging_params.email = delegate_->GetSyncSignedInEmail();
-
-  return logging_params;
-}
-
 void FeedStream::OnEnterBackground() {
   metrics_reporter_->OnEnterBackground();
   if (GetFeedConfig().upload_actions_on_enter_background) {
@@ -357,21 +335,6 @@
   }
 }
 
-bool FeedStream::IsActivityLoggingEnabled(const StreamType& stream_type) const {
-  const Stream* stream = FindStream(stream_type);
-  return stream && stream->is_activity_logging_enabled && CanUploadActions();
-}
-
-void FeedStream::UpdateIsActivityLoggingEnabled(const StreamType& stream_type) {
-  Stream& stream = GetStream(stream_type);
-
-  stream.is_activity_logging_enabled =
-      stream.model &&
-      ((stream.model->signed_in() && stream.model->logging_enabled()) ||
-       (!stream.model->signed_in() &&
-        GetFeedConfig().send_signed_out_session_logs));
-}
-
 std::string FeedStream::GetSessionId() const {
   return metadata_.session_id().token();
 }
@@ -436,14 +399,12 @@
 
   // Cancel any scheduled model unload task.
   ++stream.unload_on_detach_sequence_number;
-  upload_criteria_.SurfaceOpenedOrClosed();
 }
 
 void FeedStream::DetachSurface(FeedStreamSurface* surface) {
   Stream& stream = GetStream(surface->GetStreamType());
   metrics_reporter_->SurfaceClosed(surface->GetSurfaceId());
   stream.surfaces.SurfaceRemoved(surface);
-  upload_criteria_.SurfaceOpenedOrClosed();
   ScheduleModelUnloadIfNoSurfacesAttached(surface->GetStreamType());
 }
 
@@ -502,10 +463,6 @@
   return articles_list_visible_.GetValue();
 }
 
-std::string FeedStream::GetClientInstanceId() const {
-  return prefs::GetClientInstanceId(*profile_prefs_);
-}
-
 bool FeedStream::IsFeedEnabledByEnterprisePolicy() {
   return enable_snippets_.GetValue();
 }
@@ -557,7 +514,6 @@
   if (result.request_schedule)
     SetRequestSchedule(stream.type, *result.request_schedule);
 
-  UpdateIsActivityLoggingEnabled(stream.type);
   metrics_reporter_->OnLoadMore(
       result.stream_type, result.final_status,
       stream.model ? stream.model->GetContentStats() : ContentStats());
@@ -649,46 +605,35 @@
   return model->RejectEphemeralChange(id);
 }
 
-void FeedStream::ProcessThereAndBackAgain(base::StringPiece data) {
+void FeedStream::ProcessThereAndBackAgain(
+    base::StringPiece data,
+    const LoggingParameters& logging_parameters) {
   feedwire::ThereAndBackAgainData msg;
   msg.ParseFromArray(data.data(), data.size());
   if (msg.has_action_payload()) {
     feedwire::FeedAction action_msg;
     *action_msg.mutable_action_payload() = std::move(msg.action_payload());
-    UploadAction(std::move(action_msg), /*upload_now=*/true,
+    UploadAction(std::move(action_msg), logging_parameters,
+                 /*upload_now=*/true,
                  base::BindOnce(&FeedStream::UploadActionsComplete,
                                 base::Unretained(this)));
   }
 }
 
-void FeedStream::ProcessThereAndBackAgain(
+void FeedStream::ProcessViewAction(
     base::StringPiece data,
-    const feedui::LoggingParameters& logging_parameters) {
-  // TODO(crbug.com/1268575): Thread logging parameters to UploadActionTask when
-  // it's always available.
-  ProcessThereAndBackAgain(data);
-}
-
-void FeedStream::ProcessViewAction(base::StringPiece data) {
-  if (!CanLogViews()) {
+    const LoggingParameters& logging_parameters) {
+  if (!logging_parameters.view_actions_enabled)
     return;
-  }
 
   feedwire::FeedAction msg;
   msg.ParseFromArray(data.data(), data.size());
-  UploadAction(std::move(msg), /*upload_now=*/false,
+  UploadAction(std::move(msg), logging_parameters,
+               /*upload_now=*/false,
                base::BindOnce(&FeedStream::UploadActionsComplete,
                               base::Unretained(this)));
 }
 
-void FeedStream::ProcessViewAction(
-    base::StringPiece data,
-    const feedui::LoggingParameters& logging_parameters) {
-  // TODO(crbug.com/1268575): Thread logging parameters to UploadActionTask when
-  // it's always available.
-  ProcessViewAction(data);
-}
-
 void FeedStream::UploadActionsComplete(UploadActionsTask::Result result) {
   PopulateDebugStreamData(result, *profile_prefs_);
 }
@@ -856,7 +801,7 @@
   // be called again from within the LoadStreamTask, and then the metadata
   // will be initialized.
   if (metadata_populated_ &&
-      delegate_->GetSyncSignedInGaia() != metadata_.gaia()) {
+      delegate_->GetAccountInfo().gaia != metadata_.gaia()) {
     return {LoadStreamStatus::kDataInStoreIsForAnotherUser,
             feedwire::DiscoverLaunchResult::DATA_IN_STORE_IS_FOR_ANOTHER_USER};
   }
@@ -946,7 +891,7 @@
     // for signed-in feed, session_id token for signed-out.
     DCHECK(stream->model);
     if (stream->model->signed_in()) {
-      result.client_instance_id = GetClientInstanceId();
+      result.client_instance_id = prefs::GetClientInstanceId(*profile_prefs_);
     } else {
       result.session_id = GetSessionId();
     }
@@ -955,7 +900,7 @@
     // for signed in requests and session_id token (if any, and not expired)
     // for signed-out.
     if (IsSignedIn() && !ShouldForceSignedOutFeedQueryRequest(stream_type)) {
-      result.client_instance_id = GetClientInstanceId();
+      result.client_instance_id = prefs::GetClientInstanceId(*profile_prefs_);
     } else if (!GetSessionId().empty() && feedstore::GetSessionIdExpiryTime(
                                               metadata_) > base::Time::Now()) {
       result.session_id = GetSessionId();
@@ -1065,14 +1010,11 @@
 // Performs work that is necessary for both background and foreground load
 // tasks.
 void FeedStream::LoadTaskComplete(const LoadStreamTask::Result& result) {
-  if (delegate_->GetSyncSignedInGaia() != metadata_.gaia()) {
+  if (delegate_->GetAccountInfo().gaia != metadata_.gaia()) {
     ClearAll();
     return;
   }
   PopulateDebugStreamData(result, *profile_prefs_);
-  if (result.fetched_content_has_notice_card.has_value())
-    feed::prefs::SetLastFetchHadNoticeCard(
-        *profile_prefs_, *result.fetched_content_has_notice_card);
   if (!result.content_ids.IsEmpty()) {
     GetStream(result.stream_type).content_ids = result.content_ids;
   }
@@ -1117,8 +1059,7 @@
   has_stored_data_.SetValue(false);
   feed::prefs::SetExperiments({}, *profile_prefs_);
   feed::prefs::ClearClientInstanceId(*profile_prefs_);
-  upload_criteria_.Clear();
-  SetMetadata(feedstore::MakeMetadata(delegate_->GetSyncSignedInGaia()));
+  SetMetadata(feedstore::MakeMetadata(delegate_->GetAccountInfo().gaia));
 
   delegate_->ClearAll();
 
@@ -1150,34 +1091,25 @@
 
 void FeedStream::UploadAction(
     feedwire::FeedAction action,
+    const LoggingParameters& logging_parameters,
     bool upload_now,
     base::OnceCallback<void(UploadActionsTask::Result)> callback) {
-  if (!IsSignedIn()) {
-    DLOG(WARNING)
-        << "Called UploadActions while user is signed-out, dropping upload";
-    return;
-  }
   task_queue_.AddTask(std::make_unique<UploadActionsTask>(
-      std::move(action), upload_now, this, std::move(callback)));
+      std::move(action), upload_now, logging_parameters, this,
+      std::move(callback)));
 }
 
 void FeedStream::LoadModel(const StreamType& stream_type,
                            std::unique_ptr<StreamModel> model) {
+  DCHECK(model);
   Stream& stream = GetStream(stream_type);
   DCHECK(!stream.model);
   stream.model = std::move(model);
   stream.model->SetStreamType(stream_type);
   stream.model->SetStoreObserver(this);
 
-  // TODO(crbug.com/1268575): Once the internal changes to support per-item
-  // logging parameters is submitted, we should remove
-  // UpdateIsActivityLoggingEnabled() and instead store the logging parameters
-  // on the model.
-  UpdateIsActivityLoggingEnabled(stream_type);
-
   stream.content_ids = stream.model->GetContentIds();
-  stream.surface_updater->SetModel(stream.model.get(),
-                                   GetLoggingParameters(stream_type));
+  stream.surface_updater->SetModel(stream.model.get());
   ScheduleModelUnloadIfNoSurfacesAttached(stream_type);
   MaybeNotifyHasUnreadContent(stream_type);
 }
@@ -1210,7 +1142,7 @@
   Stream* stream = FindStream(stream_type);
   if (!stream || !stream->model)
     return;
-  stream->surface_updater->SetModel(nullptr, LoggingParameters());
+  stream->surface_updater->SetModel(nullptr);
   stream->model.reset();
 }
 
@@ -1285,16 +1217,6 @@
       stream.model->FindContentId(ToContentRevision(slice_id)));
 }
 
-// TODO(crbug/1147237): Rename this method and related members?
-bool FeedStream::CanUploadActions() const {
-  return upload_criteria_.CanUploadActions();
-}
-
-bool FeedStream::CanLogViews() const {
-  // TODO(crbug/1152592): Determine notice card behavior with web feeds.
-  return CanUploadActions();
-}
-
 // Notifies observers if 'HasUnreadContent' has changed for `stream_type`.
 // Stream content has been seen if StreamData::content_hash ==
 // Metadata::StreamMetadata::view_content_hash. This should be called:
diff --git a/components/feed/core/v2/feed_stream.h b/components/feed/core/v2/feed_stream.h
index 3c981d3..7ab5ef7c 100644
--- a/components/feed/core/v2/feed_stream.h
+++ b/components/feed/core/v2/feed_stream.h
@@ -26,11 +26,11 @@
 #include "components/feed/core/v2/persistent_key_value_store_impl.h"
 #include "components/feed/core/v2/protocol_translator.h"
 #include "components/feed/core/v2/public/feed_api.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
 #include "components/feed/core/v2/public/stream_type.h"
 #include "components/feed/core/v2/request_throttler.h"
 #include "components/feed/core/v2/scheduling.h"
 #include "components/feed/core/v2/stream/privacy_notice_card_tracker.h"
-#include "components/feed/core/v2/stream/upload_criteria.h"
 #include "components/feed/core/v2/stream_model.h"
 #include "components/feed/core/v2/stream_surface_set.h"
 #include "components/feed/core/v2/tasks/load_more_task.h"
@@ -77,8 +77,7 @@
     virtual std::string GetLanguageTag() = 0;
     virtual bool IsAutoplayEnabled() = 0;
     virtual void ClearAll() = 0;
-    virtual std::string GetSyncSignedInGaia() = 0;
-    virtual std::string GetSyncSignedInEmail() = 0;
+    virtual AccountInfo GetAccountInfo() = 0;
     virtual void PrefetchImage(const GURL& url) = 0;
     virtual void RegisterExperiments(const Experiments& experiments) = 0;
   };
@@ -100,7 +99,6 @@
   // FeedApi.
 
   WebFeedSubscriptionCoordinator& subscriptions() override;
-  bool IsActivityLoggingEnabled(const StreamType& stream_type) const override;
   std::string GetSessionId() const override;
   void AttachSurface(FeedStreamSurface*) override;
   void DetachSurface(FeedStreamSurface*) override;
@@ -109,7 +107,6 @@
   void RemoveUnreadContentObserver(const StreamType& stream_type,
                                    UnreadContentObserver* observer) override;
   bool IsArticlesListVisible() override;
-  std::string GetClientInstanceId() const override;
   void ExecuteRefreshTask(RefreshTaskId task_id) override;
   ImageFetchId FetchImage(
       const GURL& url,
@@ -133,14 +130,11 @@
                              EphemeralChangeId id) override;
   bool RejectEphemeralChange(const StreamType& stream_type,
                              EphemeralChangeId id) override;
-  void ProcessThereAndBackAgain(base::StringPiece data) override;
   void ProcessThereAndBackAgain(
       base::StringPiece data,
-      const feedui::LoggingParameters& logging_parameters) override;
-  void ProcessViewAction(base::StringPiece data) override;
-  void ProcessViewAction(
-      base::StringPiece data,
-      const feedui::LoggingParameters& logging_parameters) override;
+      const LoggingParameters& logging_parameters) override;
+  void ProcessViewAction(base::StringPiece data,
+                         const LoggingParameters& logging_parameters) override;
   bool WasUrlRecentlyNavigatedFromFeed(const GURL& url) override;
   DebugStreamData GetDebugStreamData() override;
   void ForceRefreshForDebugging(const StreamType& stream_type) override;
@@ -216,6 +210,7 @@
   // called with |true| if the consistency token was written to the store.
   void UploadAction(
       feedwire::FeedAction action,
+      const LoggingParameters& logging_parameters,
       bool upload_now,
       base::OnceCallback<void(UploadActionsTask::Result)> callback);
 
@@ -231,10 +226,8 @@
 
   void PrefetchImage(const GURL& url);
 
-  bool IsSignedIn() const { return !delegate_->GetSyncSignedInGaia().empty(); }
-  std::string GetSyncSignedInGaia() const {
-    return delegate_->GetSyncSignedInGaia();
-  }
+  bool IsSignedIn() const { return !delegate_->GetAccountInfo().IsEmpty(); }
+  AccountInfo GetAccountInfo() const { return delegate_->GetAccountInfo(); }
 
   // Determines if we should attempt loading the stream or refreshing at all.
   // Returns |LoadStreamStatus::kNoStatus| if loading may be attempted.
@@ -306,13 +299,11 @@
   }
   void SetIdleCallbackForTesting(base::RepeatingClosure idle_callback);
 
-  bool CanUploadActions() const;
-
   bool ClearAllInProgress() const { return clear_all_in_progress_; }
 
   bool IsEnabledAndVisible();
 
-  LoggingParameters GetLoggingParameters(const StreamType& stream_type);
+  PrefService* profile_prefs() const { return profile_prefs_; }
 
   base::WeakPtr<FeedStream> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
@@ -351,9 +342,6 @@
 
   void SetRequestSchedule(RefreshTaskId task_id, RequestSchedule schedule);
 
-  // Re-evaluate whether or not activity logging should currently be enabled.
-  void UpdateIsActivityLoggingEnabled(const StreamType& stream_type);
-
   // A single function task to delete stored feed data and force a refresh.
   // To only be called from within a |Task|.
   void ForceRefreshForDebuggingTask(const StreamType& stream_type);
@@ -375,8 +363,6 @@
 
   bool HasReachedConditionsToUploadActionsWithNoticeCard();
 
-  bool CanLogViews() const;
-
   void MaybeNotifyHasUnreadContent(const StreamType& stream_type);
   void EnabledPreferencesChanged();
 
@@ -431,7 +417,6 @@
   // internals page for debugging purpose.
   feedui::StreamUpdate forced_stream_update_for_debugging_;
 
-  feed_stream::UploadCriteria upload_criteria_;
   PrivacyNoticeCardTracker privacy_notice_card_tracker_;
 
   std::map<std::string, NoticeCardTracker> notice_card_trackers_;
diff --git a/components/feed/core/v2/ios_shared_prefs.h b/components/feed/core/v2/ios_shared_prefs.h
index d07a466e..abcda7f5 100644
--- a/components/feed/core/v2/ios_shared_prefs.h
+++ b/components/feed/core/v2/ios_shared_prefs.h
@@ -11,6 +11,9 @@
 namespace prefs {
 void SetLastFetchHadNoticeCard(PrefService& pref_service, bool value);
 bool GetLastFetchHadNoticeCard(const PrefService& pref_service);
+
+// TODO(b/213622639): These two functions are still used for iOS, but should
+// be removed along with any calling code.
 void SetHasReachedClickAndViewActionsUploadConditions(PrefService& pref_service,
                                                       bool value);
 bool GetHasReachedClickAndViewActionsUploadConditions(
diff --git a/components/feed/core/v2/metrics_reporter.cc b/components/feed/core/v2/metrics_reporter.cc
index 18206d6..e6527a6 100644
--- a/components/feed/core/v2/metrics_reporter.cc
+++ b/components/feed/core/v2/metrics_reporter.cc
@@ -642,7 +642,7 @@
   VVLOG << "Network Request Complete type=" << NetworkRequestTypeUmaName(type)
         << " status=" << response_info.status_code
         << " url=" << response_info.base_request_url
-        << " signed_in=" << response_info.was_signed_in
+        << " account_info=" << response_info.account_info
         << " response_size=" << response_info.encoded_size_bytes
         << " duration=" << response_info.fetch_duration;
 
diff --git a/components/feed/core/v2/protocol_translator.cc b/components/feed/core/v2/protocol_translator.cc
index be0c740..d102c1b 100644
--- a/components/feed/core/v2/protocol_translator.cc
+++ b/components/feed/core/v2/protocol_translator.cc
@@ -270,7 +270,7 @@
 RefreshResponseData TranslateWireResponse(
     feedwire::Response response,
     StreamModelUpdateRequest::Source source,
-    bool was_signed_in_request,
+    const AccountInfo& account_info,
     base::Time current_time) {
   if (response.response_version() != feedwire::Response::FEED_RESPONSE)
     return {};
@@ -330,7 +330,9 @@
     result->stream_data.set_root_event_id(
         response_metadata.event_id().SerializeAsString());
   }
-  result->stream_data.set_signed_in(was_signed_in_request);
+  result->stream_data.set_signed_in(!account_info.IsEmpty());
+  result->stream_data.set_gaia(account_info.gaia);
+  result->stream_data.set_email(account_info.email);
   result->stream_data.set_logging_enabled(
       chrome_response_metadata.logging_enabled());
   result->stream_data.set_privacy_notice_fulfilled(
@@ -340,7 +342,7 @@
   }
 
   absl::optional<std::string> session_id = absl::nullopt;
-  if (was_signed_in_request) {
+  if (!account_info.IsEmpty()) {
     // Signed-in requests don't use session_id tokens; set an empty value to
     // ensure that there are no old session_id tokens left hanging around.
     session_id = std::string();
diff --git a/components/feed/core/v2/protocol_translator.h b/components/feed/core/v2/protocol_translator.h
index 850f9c1..4551c3f 100644
--- a/components/feed/core/v2/protocol_translator.h
+++ b/components/feed/core/v2/protocol_translator.h
@@ -13,6 +13,7 @@
 #include "components/feed/core/proto/v2/store.pb.h"
 #include "components/feed/core/proto/v2/wire/data_operation.pb.h"
 #include "components/feed/core/proto/v2/wire/response.pb.h"
+#include "components/feed/core/v2/public/types.h"
 #include "components/feed/core/v2/scheduling.h"
 #include "components/feed/core/v2/types.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -89,7 +90,7 @@
 RefreshResponseData TranslateWireResponse(
     feedwire::Response response,
     StreamModelUpdateRequest::Source source,
-    bool was_signed_in_request,
+    const AccountInfo& account_info,
     base::Time current_time);
 
 std::vector<feedstore::DataOperation> TranslateDismissData(
diff --git a/components/feed/core/v2/protocol_translator_unittest.cc b/components/feed/core/v2/protocol_translator_unittest.cc
index cbde876d..8ec372bf 100644
--- a/components/feed/core/v2/protocol_translator_unittest.cc
+++ b/components/feed/core/v2/protocol_translator_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/feed/core/v2/protocol_translator.h"
 
+#include <initializer_list>
 #include <sstream>
 #include <string>
 #include <utility>
@@ -26,6 +27,12 @@
 
 const char kResponsePbPath[] = "components/test/data/feed/response.binarypb";
 const base::Time kCurrentTime = base::Time::UnixEpoch() + base::Days(123);
+AccountInfo TestAccountInfo() {
+  AccountInfo account_info;
+  account_info.gaia = "gaia";
+  account_info.email = "user@foo.com";
+  return account_info;
+}
 
 feedwire::Response TestWireResponse() {
   // Read and parse response.binarypb.
@@ -85,14 +92,14 @@
 
 // Helpers to add some common params.
 RefreshResponseData TranslateWireResponse(feedwire::Response response,
-                                          bool was_signed_in_request) {
+                                          const AccountInfo& account_info) {
   return TranslateWireResponse(response,
                                StreamModelUpdateRequest::Source::kNetworkUpdate,
-                               was_signed_in_request, kCurrentTime);
+                               account_info, kCurrentTime);
 }
 
 RefreshResponseData TranslateWireResponse(feedwire::Response response) {
-  return TranslateWireResponse(response, true);
+  return TranslateWireResponse(response, TestAccountInfo());
 }
 absl::optional<feedstore::DataOperation> TranslateDataOperation(
     feedwire::DataOperation operation) {
@@ -146,12 +153,13 @@
 
 TEST(ProtocolTranslatorTest, WasSignedInRequest) {
   feedwire::Response response = EmptyWireResponse();
-  for (bool was_signed_in_request_state : {true, false}) {
-    RefreshResponseData refresh =
-        TranslateWireResponse(response, was_signed_in_request_state);
+
+  for (AccountInfo account_info :
+       std::initializer_list<AccountInfo>{{"gaia", "user@foo.com"}, {}}) {
+    RefreshResponseData refresh = TranslateWireResponse(response, account_info);
     ASSERT_TRUE(refresh.model_update_request);
     EXPECT_EQ(refresh.model_update_request->stream_data.signed_in(),
-              was_signed_in_request_state);
+              !account_info.IsEmpty());
   }
 }
 
diff --git a/components/feed/core/v2/public/feed_api.h b/components/feed/core/v2/public/feed_api.h
index a334aab4..0126f1ac 100644
--- a/components/feed/core/v2/public/feed_api.h
+++ b/components/feed/core/v2/public/feed_api.h
@@ -22,7 +22,6 @@
 
 namespace feedui {
 class StreamUpdate;
-class LoggingParameters;
 }  // namespace feedui
 namespace feedstore {
 class DataOperation;
@@ -32,6 +31,7 @@
 class FeedStreamSurface;
 class PersistentKeyValueStore;
 class WebFeedSubscriptions;
+struct LoggingParameters;
 
 // This is the public access point for interacting with the Feed contents.
 // FeedApi serves multiple streams of data, one for each StreamType.
@@ -58,16 +58,6 @@
 
   virtual bool IsArticlesListVisible() = 0;
 
-  // Returns true if activity logging is enabled. The returned value is
-  // ephemeral, this should be called for each candidate log, as it can change
-  // as the feed is refreshed or the user signs in/out.
-  virtual bool IsActivityLoggingEnabled(
-      const StreamType& stream_type) const = 0;
-
-  // Returns the signed-in client_instance_id. This value is reset whenever the
-  // feed stream is cleared (on sign-in, sign-out, and some data clear events).
-  virtual std::string GetClientInstanceId() const = 0;
-
   // Returns the client's signed-out session id. This value is reset whenever
   // the feed stream is cleared (on sign-in, sign-out, and some data clear
   // events).
@@ -139,17 +129,15 @@
 
   // Sends 'ThereAndBackAgainData' back to the server. |data| is a serialized
   // |feedwire::ThereAndBackAgainData| message.
-  virtual void ProcessThereAndBackAgain(base::StringPiece data) = 0;
   virtual void ProcessThereAndBackAgain(
       base::StringPiece data,
-      const feedui::LoggingParameters& logging_parameters) = 0;
+      const LoggingParameters& logging_parameters) = 0;
   // Saves a view action for eventual upload. |data| is a serialized
   //|feedwire::FeedAction| message. `logging_parameters` are the logging
   // parameters associated with this item, see `feedui::StreamUpdate`.
-  virtual void ProcessViewAction(base::StringPiece data) = 0;
   virtual void ProcessViewAction(
       base::StringPiece data,
-      const feedui::LoggingParameters& logging_parameters) = 0;
+      const LoggingParameters& logging_parameters) = 0;
 
   // Returns whether `url` is a suggested Feed URLs, recently
   // navigated to by the user.
diff --git a/components/feed/core/v2/public/feed_service.cc b/components/feed/core/v2/public/feed_service.cc
index 2853fbf..b12dac1 100644
--- a/components/feed/core/v2/public/feed_service.cc
+++ b/components/feed/core/v2/public/feed_service.cc
@@ -105,9 +105,9 @@
     return service_delegate_->GetLanguageTag();
   }
 
-  std::string GetSyncSignedInGaia() override {
-    return identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
-        .gaia;
+  AccountInfo GetAccountInfo() override {
+    return AccountInfo(
+        identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync));
   }
 
  private:
@@ -151,13 +151,9 @@
   void PrefetchImage(const GURL& url) override {
     service_delegate_->PrefetchImage(url);
   }
-  std::string GetSyncSignedInGaia() override {
-    return identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
-        .gaia;
-  }
-  std::string GetSyncSignedInEmail() override {
-    return identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
-        .email;
+  AccountInfo GetAccountInfo() override {
+    return AccountInfo(
+        identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync));
   }
   void RegisterExperiments(const Experiments& experiments) override {
     service_delegate_->RegisterExperiments(experiments);
diff --git a/components/feed/core/v2/public/logging_parameters.cc b/components/feed/core/v2/public/logging_parameters.cc
new file mode 100644
index 0000000..ae64b4c
--- /dev/null
+++ b/components/feed/core/v2/public/logging_parameters.cc
@@ -0,0 +1,74 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/feed/core/v2/public/logging_parameters.h"
+
+#include "base/logging.h"
+#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/proto/v2/ui.pb.h"
+#include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/protocol_translator.h"
+
+namespace feed {
+
+LoggingParameters::LoggingParameters() = default;
+LoggingParameters::~LoggingParameters() = default;
+LoggingParameters::LoggingParameters(const LoggingParameters&) = default;
+LoggingParameters::LoggingParameters(LoggingParameters&&) = default;
+LoggingParameters& LoggingParameters::operator=(const LoggingParameters&) =
+    default;
+
+bool LoggingParameters::operator==(const LoggingParameters& rhs) const {
+  return std::tie(email, client_instance_id, logging_enabled,
+                  view_actions_enabled, root_event_id) ==
+         std::tie(rhs.email, rhs.client_instance_id, logging_enabled,
+                  view_actions_enabled, root_event_id);
+}
+
+LoggingParameters MakeLoggingParameters(
+    const std::string client_instance_id,
+    const StreamModelUpdateRequest& update_request) {
+  const feedstore::StreamData& stream_data = update_request.stream_data;
+  bool signed_in = stream_data.signed_in() && !stream_data.email().empty() &&
+                   !stream_data.gaia().empty();
+
+  LoggingParameters logging_params;
+  logging_params.client_instance_id = client_instance_id;
+  logging_params.root_event_id = stream_data.root_event_id();
+  logging_params.logging_enabled =
+      ((signed_in && stream_data.logging_enabled()) ||
+       (!signed_in && GetFeedConfig().send_signed_out_session_logs));
+  logging_params.view_actions_enabled = logging_params.logging_enabled;
+
+  if (signed_in) {
+    DCHECK(!stream_data.email().empty());
+    DCHECK(!stream_data.gaia().empty());
+    // We provide account name even if logging is disabled, so that account
+    // name can be verified for action uploads.
+    logging_params.email = stream_data.email();
+  }
+
+  return logging_params;
+}
+
+LoggingParameters FromProto(const feedui::LoggingParameters& proto) {
+  LoggingParameters result;
+  result.email = proto.email();
+  result.client_instance_id = proto.client_instance_id();
+  result.logging_enabled = proto.logging_enabled();
+  result.view_actions_enabled = proto.view_actions_enabled();
+  result.root_event_id = proto.root_event_id();
+  return result;
+}
+
+void ToProto(const LoggingParameters& logging_parameters,
+             feedui::LoggingParameters& proto) {
+  proto.set_email(logging_parameters.email);
+  proto.set_client_instance_id(logging_parameters.client_instance_id);
+  proto.set_logging_enabled(logging_parameters.logging_enabled);
+  proto.set_view_actions_enabled(logging_parameters.view_actions_enabled);
+  proto.set_root_event_id(logging_parameters.root_event_id);
+}
+
+}  // namespace feed
diff --git a/components/feed/core/v2/public/logging_parameters.h b/components/feed/core/v2/public/logging_parameters.h
new file mode 100644
index 0000000..b206cf9
--- /dev/null
+++ b/components/feed/core/v2/public/logging_parameters.h
@@ -0,0 +1,48 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FEED_CORE_V2_PUBLIC_LOGGING_PARAMETERS_H_
+#define COMPONENTS_FEED_CORE_V2_PUBLIC_LOGGING_PARAMETERS_H_
+
+#include <string>
+
+namespace feedui {
+class LoggingParameters;
+}
+
+namespace feed {
+struct StreamModelUpdateRequest;
+
+struct LoggingParameters {
+  LoggingParameters();
+  ~LoggingParameters();
+  LoggingParameters(const LoggingParameters&);
+  LoggingParameters(LoggingParameters&&);
+  LoggingParameters& operator=(const LoggingParameters&);
+
+  // User ID, if the user is signed-in.
+  std::string email;
+  // A unique ID for this client. Used for reliability logging.
+  std::string client_instance_id;
+  // Whether attention / interaction logging is enabled.
+  bool logging_enabled = false;
+  // Whether view actions may be recorded.
+  bool view_actions_enabled = false;
+  // EventID of the first page response.
+  std::string root_event_id;
+
+  bool operator==(const LoggingParameters& rhs) const;
+};
+
+LoggingParameters MakeLoggingParameters(
+    const std::string client_instance_id,
+    const StreamModelUpdateRequest& update_request);
+
+LoggingParameters FromProto(const feedui::LoggingParameters& proto);
+void ToProto(const LoggingParameters& logging_parameters,
+             feedui::LoggingParameters& proto);
+
+}  // namespace feed
+
+#endif  // COMPONENTS_FEED_CORE_V2_PUBLIC_LOGGING_PARAMETERS_H_
diff --git a/components/feed/core/v2/public/logging_parameters_unittest.cc b/components/feed/core/v2/public/logging_parameters_unittest.cc
new file mode 100644
index 0000000..ab0e1b8a
--- /dev/null
+++ b/components/feed/core/v2/public/logging_parameters_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/feed/core/v2/public/logging_parameters.h"
+
+#include "components/feed/core/proto/v2/ui.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feed {
+
+TEST(LoggingParameters, ToFromProto_Set) {
+  LoggingParameters params;
+  params.email = "foo@bar.com";
+  params.client_instance_id = "instanceid";
+  params.logging_enabled = true;
+  params.view_actions_enabled = true;
+
+  feedui::LoggingParameters proto;
+  ToProto(params, proto);
+
+  EXPECT_EQ("foo@bar.com", proto.email());
+  EXPECT_EQ("instanceid", proto.client_instance_id());
+  EXPECT_EQ(true, proto.logging_enabled());
+  EXPECT_EQ(true, proto.view_actions_enabled());
+  EXPECT_EQ(params, FromProto(proto));
+}
+
+TEST(LoggingParameters, ToFromProto_Empty) {
+  LoggingParameters params;
+
+  feedui::LoggingParameters proto;
+  ToProto(params, proto);
+
+  EXPECT_EQ("", proto.email());
+  EXPECT_EQ("", proto.client_instance_id());
+  EXPECT_EQ(false, proto.logging_enabled());
+  EXPECT_EQ(false, proto.view_actions_enabled());
+  EXPECT_EQ(params, FromProto(proto));
+}
+
+}  // namespace feed
diff --git a/components/feed/core/v2/public/public_types.cc b/components/feed/core/v2/public/public_types.cc
index ee95906..08cb533 100644
--- a/components/feed/core/v2/public/public_types.cc
+++ b/components/feed/core/v2/public/public_types.cc
@@ -5,8 +5,32 @@
 #include "components/feed/core/v2/public/types.h"
 
 #include <ostream>
+#include <tuple>
+#include "components/feed/core/proto/v2/ui.pb.h"
 
 namespace feed {
+
+AccountInfo::AccountInfo() = default;
+AccountInfo::AccountInfo(const std::string& gaia, const std::string& email)
+    : gaia(gaia), email(email) {}
+AccountInfo::AccountInfo(CoreAccountInfo account_info)
+    : gaia(std::move(account_info.gaia)),
+      email(std::move(account_info.email)) {}
+bool AccountInfo::IsEmpty() const {
+  DCHECK_EQ(gaia.empty(), email.empty());
+  return gaia.empty();
+}
+bool AccountInfo::operator==(const AccountInfo& rhs) const {
+  return tie(gaia, email) == tie(rhs.gaia, rhs.email);
+}
+
+std::ostream& operator<<(std::ostream& os, const AccountInfo& o) {
+  if (o.IsEmpty()) {
+    return os << "signed-out";
+  }
+  return os << o.gaia << ":" << o.email;
+}
+
 WebFeedMetadata::WebFeedMetadata() = default;
 WebFeedMetadata::WebFeedMetadata(const WebFeedMetadata&) = default;
 WebFeedMetadata::WebFeedMetadata(WebFeedMetadata&&) = default;
@@ -63,7 +87,7 @@
             << " bless_nonce=" << o.bless_nonce
             << " base_request_url=" << o.base_request_url
             << " response_body_bytes=" << o.response_body_bytes
-            << " was_signed_in=" << o.was_signed_in << "}";
+            << " account_info=" << o.account_info << "}";
 }
 
 std::ostream& operator<<(std::ostream& out, WebFeedSubscriptionStatus value) {
diff --git a/components/feed/core/v2/public/test/stub_feed_api.cc b/components/feed/core/v2/public/test/stub_feed_api.cc
index 4be0f11..00f0f362 100644
--- a/components/feed/core/v2/public/test/stub_feed_api.cc
+++ b/components/feed/core/v2/public/test/stub_feed_api.cc
@@ -20,13 +20,6 @@
 bool StubFeedApi::IsArticlesListVisible() {
   return {};
 }
-bool StubFeedApi::IsActivityLoggingEnabled(
-    const StreamType& stream_type) const {
-  return {};
-}
-std::string StubFeedApi::GetClientInstanceId() const {
-  return {};
-}
 std::string StubFeedApi::GetSessionId() const {
   return {};
 }
diff --git a/components/feed/core/v2/public/test/stub_feed_api.h b/components/feed/core/v2/public/test/stub_feed_api.h
index 16abc85..0d98447e 100644
--- a/components/feed/core/v2/public/test/stub_feed_api.h
+++ b/components/feed/core/v2/public/test/stub_feed_api.h
@@ -37,8 +37,6 @@
   void RemoveUnreadContentObserver(const StreamType& stream_type,
                                    UnreadContentObserver* observer) override {}
   bool IsArticlesListVisible() override;
-  bool IsActivityLoggingEnabled(const StreamType& stream_type) const override;
-  std::string GetClientInstanceId() const override;
   std::string GetSessionId() const override;
   void ExecuteRefreshTask(RefreshTaskId task_id) override {}
   void LoadMore(const FeedStreamSurface& surface,
@@ -63,14 +61,12 @@
                              EphemeralChangeId id) override;
   bool RejectEphemeralChange(const StreamType& stream_type,
                              EphemeralChangeId id) override;
-  void ProcessThereAndBackAgain(base::StringPiece data) override {}
   void ProcessThereAndBackAgain(
       base::StringPiece data,
-      const feedui::LoggingParameters& logging_parameters) override {}
-  void ProcessViewAction(base::StringPiece data) override {}
-  void ProcessViewAction(
-      base::StringPiece data,
-      const feedui::LoggingParameters& logging_parameters) override {}
+      const LoggingParameters& logging_parameters) override {}
+  void ProcessViewAction(base::StringPiece data,
+                         const LoggingParameters& logging_parameters) override {
+  }
   bool WasUrlRecentlyNavigatedFromFeed(const GURL& url) override;
   void ReportSliceViewed(SurfaceId surface_id,
                          const StreamType& stream_type,
diff --git a/components/feed/core/v2/public/types.h b/components/feed/core/v2/public/types.h
index 6dcf6a7..522a8d0 100644
--- a/components/feed/core/v2/public/types.h
+++ b/components/feed/core/v2/public/types.h
@@ -13,16 +13,33 @@
 #include "base/time/time.h"
 #include "base/types/id_type.h"
 #include "base/version.h"
+#include "components/signin/public/identity_manager/account_info.h"
 #include "components/version_info/channel.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
 
 namespace feed {
 
+// Information about the user account. Currently, for Feed purposes, we use
+// account information only when the user is signed-in with Sync enabled. If
+// Sync is disabled, AccountInfo should be empty.
+struct AccountInfo {
+  AccountInfo();
+  AccountInfo(const std::string& gaia, const std::string& email);
+  explicit AccountInfo(CoreAccountInfo account_info);
+  bool operator==(const AccountInfo& rhs) const;
+  bool operator!=(const AccountInfo& rhs) const { return !(*this == rhs); }
+  bool IsEmpty() const;
+
+  std::string gaia;
+  std::string email;
+};
+std::ostream& operator<<(std::ostream& os, const AccountInfo& o);
+
 enum class RefreshTaskId {
   kRefreshForYouFeed,
-  // TODO(1152592): Refresh is not currently used for the Web Feed. Remove this
-  // code if we don't need it.
+  // TODO(1152592): Refresh is not currently used for the Web Feed. Remove
+  // this code if we don't need it.
   kRefreshWebFeed,
 };
 
@@ -63,7 +80,8 @@
   GURL base_request_url;
   size_t response_body_bytes = 0;
   size_t encoded_size_bytes = 0;
-  bool was_signed_in = false;
+  // If it was a signed-in request, this is the associated account info.
+  AccountInfo account_info;
   base::TimeTicks fetch_time_ticks;
   base::TimeTicks loader_start_time_ticks;
 };
@@ -99,8 +117,8 @@
 absl::optional<DebugStreamData> DeserializeDebugStreamData(
     base::StringPiece base64_encoded);
 
-// Information about a web page which may be used to determine an associated web
-// feed.
+// Information about a web page which may be used to determine an associated
+// web feed.
 class WebFeedPageInformation {
  public:
   WebFeedPageInformation();
@@ -176,9 +194,9 @@
 };
 std::ostream& operator<<(std::ostream& out, const WebFeedMetadata& value);
 
-// This must be kept in sync with WebFeedSubscriptionRequestStatus in enums.xml.
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
+// This must be kept in sync with WebFeedSubscriptionRequestStatus in
+// enums.xml. These values are persisted to logs. Entries should not be
+// renumbered and numeric values should never be reused.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.feed.webfeed
 enum class WebFeedSubscriptionRequestStatus {
   kUnknown = 0,
diff --git a/components/feed/core/v2/stream/privacy_notice_card_tracker.cc b/components/feed/core/v2/stream/privacy_notice_card_tracker.cc
index 3170abc..8062a7b 100644
--- a/components/feed/core/v2/stream/privacy_notice_card_tracker.cc
+++ b/components/feed/core/v2/stream/privacy_notice_card_tracker.cc
@@ -43,19 +43,6 @@
   if (!IsPrivacyNoticeCard(content_id))
     return;
 
-  // Do two things if the notice card was viewed:
-  // * If kInterestFeedV2ClicksAndViewsConditionalUpload is enabled, remember
-  // the notice card was viewed.
-  // * If the notice card is viewed and auto-dismiss is enabled, increment view
-  // count.
-
-  if (is_signed_in &&
-      base::FeatureList::IsEnabled(
-          feed::kInterestFeedV2ClicksAndViewsConditionalUpload)) {
-    feed::prefs::SetHasReachedClickAndViewActionsUploadConditions(
-        *profile_prefs_, true);
-  }
-
   auto now = base::TimeTicks::Now();
   if (now - last_view_time_ < base::Minutes(5))
     return;
diff --git a/components/feed/core/v2/stream/upload_criteria.cc b/components/feed/core/v2/stream/upload_criteria.cc
deleted file mode 100644
index 035f2aa..0000000
--- a/components/feed/core/v2/stream/upload_criteria.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/feed/core/v2/stream/upload_criteria.h"
-
-#include "base/feature_list.h"
-#include "components/feed/core/v2/ios_shared_prefs.h"
-#include "components/feed/core/v2/prefs.h"
-#include "components/feed/core/v2/stream/notice_card_tracker.h"
-#include "components/feed/feed_feature_list.h"
-#include "components/prefs/pref_service.h"
-
-namespace feed {
-namespace feed_stream {
-
-UploadCriteria::UploadCriteria(PrefService* profile_prefs)
-    : profile_prefs_(profile_prefs) {
-  UpdateCanUploadActionsWithNoticeCard();
-}
-
-bool UploadCriteria::CanUploadActions() const {
-  return can_upload_actions_with_notice_card_ ||
-         !feed::prefs::GetLastFetchHadNoticeCard(*profile_prefs_);
-}
-
-void UploadCriteria::SurfaceOpenedOrClosed() {
-  UpdateCanUploadActionsWithNoticeCard();
-}
-
-void UploadCriteria::Clear() {
-  // Set this to false since we don't know whether there will be a notice card.
-  feed::prefs::SetLastFetchHadNoticeCard(*profile_prefs_, true);
-  feed::prefs::SetHasReachedClickAndViewActionsUploadConditions(*profile_prefs_,
-                                                                false);
-  can_upload_actions_with_notice_card_ = false;
-}
-
-bool UploadCriteria::HasReachedConditionsToUploadActionsWithNoticeCard() {
-  if (base::FeatureList::IsEnabled(
-          feed::kInterestFeedV2ClicksAndViewsConditionalUpload)) {
-    return feed::prefs::GetHasReachedClickAndViewActionsUploadConditions(
-        *profile_prefs_);
-  }
-  // Consider the conditions as already reached to enable uploads when the
-  // feature is disabled. This will also have the effect of not updating the
-  // related pref.
-  return true;
-}
-
-void UploadCriteria::UpdateCanUploadActionsWithNoticeCard() {
-  can_upload_actions_with_notice_card_ =
-      HasReachedConditionsToUploadActionsWithNoticeCard();
-}
-
-}  // namespace feed_stream
-}  // namespace feed
diff --git a/components/feed/core/v2/stream/upload_criteria.h b/components/feed/core/v2/stream/upload_criteria.h
deleted file mode 100644
index a1b1440..0000000
--- a/components/feed/core/v2/stream/upload_criteria.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_FEED_CORE_V2_STREAM_UPLOAD_CRITERIA_H_
-#define COMPONENTS_FEED_CORE_V2_STREAM_UPLOAD_CRITERIA_H_
-
-#include "base/memory/raw_ptr.h"
-
-class PrefService;
-
-namespace feed {
-namespace feed_stream {
-
-// Determines whether we can upload actions.
-class UploadCriteria {
- public:
-  explicit UploadCriteria(PrefService* profile_prefs);
-  UploadCriteria(const UploadCriteria&) = delete;
-  UploadCriteria& operator=(const UploadCriteria&) = delete;
-
-  bool CanUploadActions() const;
-
-  // Events to update criteria.
-  void SurfaceOpenedOrClosed();
-  void Clear();
-
- private:
-  bool HasReachedConditionsToUploadActionsWithNoticeCard();
-  void UpdateCanUploadActionsWithNoticeCard();
-
-  raw_ptr<PrefService> profile_prefs_;
-  // Whether the feed stream can upload actions with the notice card in the
-  // feed. This is cached so that we enable uploads in the session after the
-  // criteria was met.
-  bool can_upload_actions_with_notice_card_ = false;
-};
-
-}  // namespace feed_stream
-}  // namespace feed
-
-#endif  // COMPONENTS_FEED_CORE_V2_STREAM_UPLOAD_CRITERIA_H_
diff --git a/components/feed/core/v2/stream_model.cc b/components/feed/core/v2/stream_model.cc
index dc0e024..6d3c9db 100644
--- a/components/feed/core/v2/stream_model.cc
+++ b/components/feed/core/v2/stream_model.cc
@@ -19,6 +19,7 @@
 #include "components/feed/core/v2/feedstore_util.h"
 #include "components/feed/core/v2/proto_util.h"
 #include "components/feed/core/v2/protocol_translator.h"
+#include "components/feed/core/v2/types.h"
 
 namespace feed {
 namespace {
@@ -64,8 +65,10 @@
 StoreUpdate::StoreUpdate(StoreUpdate&&) = default;
 StoreUpdate& StoreUpdate::operator=(StoreUpdate&&) = default;
 
-StreamModel::StreamModel(Context* context)
-    : content_map_(&(context->revision_generator)) {}
+StreamModel::StreamModel(Context* context,
+                         const LoggingParameters& logging_parameters)
+    : logging_parameters_(logging_parameters),
+      content_map_(&(context->revision_generator)) {}
 
 StreamModel::~StreamModel() = default;
 
diff --git a/components/feed/core/v2/stream_model.h b/components/feed/core/v2/stream_model.h
index e939442..d53af5d4 100644
--- a/components/feed/core/v2/stream_model.h
+++ b/components/feed/core/v2/stream_model.h
@@ -17,6 +17,7 @@
 #include "components/feed/core/proto/v2/store.pb.h"
 #include "components/feed/core/proto/v2/wire/content_id.pb.h"
 #include "components/feed/core/v2/proto_util.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
 #include "components/feed/core/v2/public/stream_type.h"
 #include "components/feed/core/v2/stream_model/ephemeral_change.h"
 #include "components/feed/core/v2/stream_model/feature_tree.h"
@@ -90,9 +91,7 @@
     virtual void OnStoreChange(StoreUpdate update) = 0;
   };
 
-  // TODO(crbug.com/1268575): Add LoggingParameters here, as they should stay
-  // constant over the life of the model.
-  explicit StreamModel(Context* context);
+  StreamModel(Context* context, const LoggingParameters& logging_parameters);
   ~StreamModel();
 
   StreamModel(const StreamModel& src) = delete;
@@ -105,6 +104,10 @@
 
   // Data access.
 
+  const LoggingParameters& GetLoggingParameters() const {
+    return logging_parameters_;
+  }
+
   // Was this feed signed in.
   bool signed_in() const { return stream_data_.signed_in(); }
 
@@ -177,6 +180,7 @@
 
   void UpdateFlattenedTree();
 
+  const LoggingParameters logging_parameters_;
   // The stream type for which this model is used. Used only for forwarding to
   // observers.
   StreamType stream_type_;
diff --git a/components/feed/core/v2/stream_model_unittest.cc b/components/feed/core/v2/stream_model_unittest.cc
index 6cb9471..2e562f8 100644
--- a/components/feed/core/v2/stream_model_unittest.cc
+++ b/components/feed/core/v2/stream_model_unittest.cc
@@ -14,6 +14,7 @@
 #include "components/feed/core/proto/v2/wire/content_id.pb.h"
 #include "components/feed/core/v2/protocol_translator.h"
 #include "components/feed/core/v2/test/stream_builder.h"
+#include "components/feed/core/v2/types.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -73,7 +74,7 @@
 
 TEST(StreamModelTest, ConstructEmptyModel) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   EXPECT_EQ(0UL, model.GetContentList().size());
@@ -81,7 +82,7 @@
 
 TEST(StreamModelTest, ExecuteOperationsTypicalStream) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
   TestStoreObserver store_observer(&model);
 
@@ -95,7 +96,7 @@
 
 TEST(StreamModelTest, AddContentWithoutRoot) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   std::vector<feedstore::DataOperation> operations{
@@ -112,7 +113,7 @@
 // Verify Stream -> Content works.
 TEST(StreamModelTest, AddStreamContent) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   std::vector<feedstore::DataOperation> operations{
@@ -128,7 +129,7 @@
 TEST(StreamModelTest, AddRootAsChild) {
   // When the root is added as a child, it's no longer considered a root.
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
   feedstore::StreamStructure stream_with_parent = MakeStream();
   *stream_with_parent.mutable_parent_id() = MakeContentContentId(0);
@@ -146,7 +147,7 @@
 
 TEST(StreamModelTest, RemoveCluster) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   std::vector<feedstore::DataOperation> operations =
@@ -160,7 +161,7 @@
 
 TEST(StreamModelTest, RemoveContent) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   std::vector<feedstore::DataOperation> operations =
@@ -174,7 +175,7 @@
 
 TEST(StreamModelTest, RemoveRoot) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   std::vector<feedstore::DataOperation> operations =
@@ -188,7 +189,7 @@
 
 TEST(StreamModelTest, RemoveAndAddRoot) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   std::vector<feedstore::DataOperation> operations =
@@ -203,7 +204,7 @@
 
 TEST(StreamModelTest, SecondRootStreamIsIgnored) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   // Add a second stream root, but it is ignored.
@@ -226,7 +227,7 @@
 
 TEST(StreamModelTest, SecondRootWithIsRootIsSelected) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   // Set up operations which add two roots. The second root is chosen because it
@@ -246,7 +247,7 @@
   // Remove a cluster and add it back. Adding it back keeps its original
   // placement.
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   std::vector<feedstore::DataOperation> operations =
@@ -262,7 +263,7 @@
 TEST(StreamModelTest, RemoveAndAppendToNewParent) {
   // Attempt to re-parent a node. This is not allowed, the old parent remains.
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   std::vector<feedstore::DataOperation> operations =
@@ -277,7 +278,7 @@
 
 TEST(StreamModelTest, EphemeralNewCluster) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   model.ExecuteOperations(MakeTypicalStreamOperations());
@@ -296,7 +297,7 @@
 
 TEST(StreamModelTest, CommitEphemeralChange) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   model.ExecuteOperations(MakeTypicalStreamOperations());
@@ -329,7 +330,7 @@
 
 TEST(StreamModelTest, RejectEphemeralChange) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   model.ExecuteOperations(MakeTypicalStreamOperations());
@@ -350,7 +351,7 @@
 
 TEST(StreamModelTest, RejectFirstEphemeralChange) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
 
   model.ExecuteOperations(MakeTypicalStreamOperations());
@@ -378,7 +379,7 @@
 
 TEST(StreamModelTest, InitialLoad) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
   TestStoreObserver store_observer(&model);
   model.Update(MakeTypicalInitialModelState());
@@ -397,7 +398,7 @@
 
 TEST(StreamModelTest, StoreObserverReceivesIncreasingSequenceNumbers) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
   TestStoreObserver store_observer(&model);
 
@@ -423,7 +424,7 @@
 
 TEST(StreamModelTest, SharedStateCanBeAddedOnlyOnce) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
   TestStoreObserver store_observer(&model);
 
@@ -447,7 +448,7 @@
 
 TEST(StreamModelTest, SharedStateUpdatesKeepOriginal) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
   TestStoreObserver store_observer(&model);
   model.Update(MakeTypicalInitialModelState());
@@ -469,7 +470,7 @@
 
 TEST(StreamModelTest, ClearAllErasesSharedStates) {
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters());
   TestObserver observer(&model);
   TestStoreObserver store_observer(&model);
   // CLEAR_ALL is the first operation in the typical initial model state.
diff --git a/components/feed/core/v2/surface_updater.cc b/components/feed/core/v2/surface_updater.cc
index 1a60ffcc..c0f35be 100644
--- a/components/feed/core/v2/surface_updater.cc
+++ b/components/feed/core/v2/surface_updater.cc
@@ -85,7 +85,6 @@
     const std::vector<std::string>& updated_shared_state_ids,
     const base::flat_set<ContentRevision>& already_sent_content,
     const StreamModel* model,
-    const LoggingParameters& logging_parameters,
     const DrawState& state) {
   DCHECK(!state.loading_initial || !state.loading_more)
       << "logic bug: requested both top and bottom spinners.";
@@ -137,25 +136,24 @@
   if (model) {
     update.stream_update.set_fetch_time_ms(
         model->GetLastAddedTime().ToDeltaSinceWindowsEpoch().InMilliseconds());
+    ToProto(model->GetLoggingParameters(),
+            *update.stream_update.mutable_logging_parameters());
+  } else {
+    ToProto(LoggingParameters{},
+            *update.stream_update.mutable_logging_parameters());
   }
 
-  ToProto(logging_parameters,
-          *update.stream_update.mutable_logging_parameters());
-
   return update;
 }
 
-StreamUpdateAndType GetUpdateForNewSurface(
-    const DrawState& state,
-    const StreamModel* model,
-    const LoggingParameters& logging_parameters) {
+StreamUpdateAndType GetUpdateForNewSurface(const DrawState& state,
+                                           const StreamModel* model) {
   std::vector<std::string> updated_shared_state_ids;
   if (model) {
     updated_shared_state_ids = model->GetSharedStateIds();
   }
   return MakeStreamUpdate(std::move(updated_shared_state_ids),
-                          /*already_sent_content=*/{}, model,
-                          logging_parameters, state);
+                          /*already_sent_content=*/{}, model, state);
 }
 
 base::flat_set<ContentRevision> GetContentSet(const StreamModel* model) {
@@ -218,14 +216,12 @@
 
 SurfaceUpdater::~SurfaceUpdater() = default;
 
-void SurfaceUpdater::SetModel(StreamModel* model,
-                              const LoggingParameters& logging_parameters) {
+void SurfaceUpdater::SetModel(StreamModel* model) {
   if (model_ == model)
     return;
   if (model_)
     model_->RemoveObserver(this);
   model_ = model;
-  logging_parameters_ = logging_parameters;
   sent_content_.clear();
   if (model_) {
     model_->AddObserver(this);
@@ -264,8 +260,7 @@
     logger.LogLaunchFinishedAfterStreamUpdate(loading_not_allowed_reason);
   }
 
-  StreamUpdateAndType update =
-      GetUpdateForNewSurface(GetState(), model_, logging_parameters_);
+  StreamUpdateAndType update = GetUpdateForNewSurface(GetState(), model_);
   launch_reliability_logger_.OnStreamUpdate(update.type, *surface);
   SendUpdateToSurface(surface, update.stream_update);
 
@@ -346,8 +341,7 @@
     const std::vector<std::string>& updated_shared_state_ids) {
   DrawState state = GetState();
   StreamUpdateAndType update =
-      MakeStreamUpdate(updated_shared_state_ids, sent_content_, model_,
-                       logging_parameters_, state);
+      MakeStreamUpdate(updated_shared_state_ids, sent_content_, model_, state);
 
   if (load_stream_started_ && !loading_more_)
     launch_reliability_logger_.OnStreamUpdate(update.type);
diff --git a/components/feed/core/v2/surface_updater.h b/components/feed/core/v2/surface_updater.h
index 416f582..1b330e0 100644
--- a/components/feed/core/v2/surface_updater.h
+++ b/components/feed/core/v2/surface_updater.h
@@ -45,8 +45,7 @@
   // surfaces, so they will keep any content they may have been displaying
   // before. We don't send a zero-state in this case, since we might want to
   // immediately trigger a load.
-  void SetModel(StreamModel* model,
-                const LoggingParameters& logging_parameters);
+  void SetModel(StreamModel* model);
 
   // StreamModel::Observer.
   void OnUiUpdate(const StreamModel::UiUpdate& update) override;
@@ -110,7 +109,6 @@
   bool loading_more_ = false;
   bool loading_initial_ = false;
   bool load_stream_failed_ = false;
-  LoggingParameters logging_parameters_;
   LoadStreamStatus load_stream_status_ = LoadStreamStatus::kNoStatus;
 
   // The |DrawState| when the last update was sent to all surfaces.
diff --git a/components/feed/core/v2/tasks/load_more_task.cc b/components/feed/core/v2/tasks/load_more_task.cc
index b13b998..390dc4b08c 100644
--- a/components/feed/core/v2/tasks/load_more_task.cc
+++ b/components/feed/core/v2/tasks/load_more_task.cc
@@ -80,8 +80,8 @@
   // content determines the sign-in state of the subsequent load more requests.
   // This avoids a possible situation where there would be a mix of signed-in
   // and signed-out content, which we don't want.
-  std::string gaia =
-      model->signed_in() ? stream_.GetSyncSignedInGaia() : std::string();
+  AccountInfo account_info =
+      model->signed_in() ? stream_.GetAccountInfo() : AccountInfo{};
   // Send network request.
   fetch_start_time_ = base::TimeTicks::Now();
 
@@ -95,11 +95,11 @@
   // WebFeeds.
   if (base::FeatureList::IsEnabled(kDiscoFeedEndpoint)) {
     stream_.GetNetwork().SendApiRequest<QueryNextPageDiscoverApi>(
-        request, gaia,
+        request, account_info,
         base::BindOnce(&LoadMoreTask::QueryApiRequestComplete, GetWeakPtr()));
   } else {
     stream_.GetNetwork().SendQueryRequest(
-        NetworkRequestType::kNextPage, request, gaia,
+        NetworkRequestType::kNextPage, request, account_info,
         base::BindOnce(&LoadMoreTask::QueryRequestComplete, GetWeakPtr()));
   }
 }
@@ -128,7 +128,7 @@
   RefreshResponseData translated_response =
       stream_.GetWireResponseTranslator().TranslateWireResponse(
           *response_body, StreamModelUpdateRequest::Source::kNetworkLoadMore,
-          response_info.was_signed_in, base::Time::Now());
+          response_info.account_info, base::Time::Now());
 
   if (!translated_response.model_update_request)
     return Done(LoadStreamStatus::kProtoTranslationFailed);
diff --git a/components/feed/core/v2/tasks/load_stream_from_store_task.cc b/components/feed/core/v2/tasks/load_stream_from_store_task.cc
index 01a6f464..bda6f54 100644
--- a/components/feed/core/v2/tasks/load_stream_from_store_task.cc
+++ b/components/feed/core/v2/tasks/load_stream_from_store_task.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/check.h"
 #include "base/time/time.h"
 #include "components/feed/core/proto/v2/store.pb.h"
 #include "components/feed/core/proto/v2/wire/reliability_logging_enums.pb.h"
@@ -65,6 +66,26 @@
              feedwire::DiscoverCardReadCacheResult::EMPTY_SESSION);
     return;
   }
+  if (!ignore_account_) {
+    const AccountInfo& account_info = feed_stream_.GetAccountInfo();
+    if (result.stream_data.signed_in() && result.stream_data.gaia().empty()) {
+      // TODO(crbug.com/1268575): For backward compatibility, set the gaia in
+      // stream_data if it is unset. Remove this code after it's been in at
+      // least one Chrome release.
+      result.stream_data.set_gaia(account_info.gaia);
+      result.stream_data.set_email(account_info.email);
+    }
+
+    if (result.stream_data.signed_in()) {
+      if (result.stream_data.gaia() != account_info.gaia ||
+          result.stream_data.email() != account_info.email) {
+        Complete(LoadStreamStatus::kDataInStoreIsForAnotherUser,
+                 feedwire::DiscoverCardReadCacheResult::FAILED);
+        return;
+      }
+    }
+  }
+
   content_ids_ = feedstore::GetContentIds(result.stream_data);
   if (!ignore_staleness_) {
     content_age_ =
diff --git a/components/feed/core/v2/tasks/load_stream_from_store_task.h b/components/feed/core/v2/tasks/load_stream_from_store_task.h
index 88bf7e9..ab5aedb 100644
--- a/components/feed/core/v2/tasks/load_stream_from_store_task.h
+++ b/components/feed/core/v2/tasks/load_stream_from_store_task.h
@@ -67,6 +67,7 @@
   LoadStreamFromStoreTask& operator=(const LoadStreamFromStoreTask&) = delete;
 
   void IgnoreStalenessForTesting() { ignore_staleness_ = true; }
+  void IngoreAccountForTesting() { ignore_account_ = true; }
 
  private:
   void Run() override;
@@ -88,6 +89,7 @@
   raw_ptr<FeedStore> store_;  // Unowned.
   bool ignore_staleness_ = false;
   bool missed_last_refresh_ = false;
+  bool ignore_account_ = false;
   base::OnceCallback<void(Result)> result_callback_;
 
   // Data to be stuffed into the Result when the task is complete.
diff --git a/components/feed/core/v2/tasks/load_stream_task.cc b/components/feed/core/v2/tasks/load_stream_task.cc
index 264e75b..5f2b263 100644
--- a/components/feed/core/v2/tasks/load_stream_task.cc
+++ b/components/feed/core/v2/tasks/load_stream_task.cc
@@ -22,6 +22,7 @@
 #include "components/feed/core/v2/feed_network.h"
 #include "components/feed/core/v2/feed_stream.h"
 #include "components/feed/core/v2/feedstore_util.h"
+#include "components/feed/core/v2/ios_shared_prefs.h"
 #include "components/feed/core/v2/metrics_reporter.h"
 #include "components/feed/core/v2/proto_util.h"
 #include "components/feed/core/v2/protocol_translator.h"
@@ -252,9 +253,8 @@
       GetRequestReason(options_.stream_type, options_.load_type),
       request_metadata, stream_.GetMetadata().consistency_token());
 
-  const std::string gaia =
-      force_signed_out_request ? std::string() : stream_.GetSyncSignedInGaia();
-
+  const AccountInfo account_info =
+      force_signed_out_request ? AccountInfo{} : stream_.GetAccountInfo();
   stream_.GetMetricsReporter().NetworkRefreshRequestStarted(
       options_.stream_type, request_metadata.content_order);
 
@@ -265,7 +265,7 @@
     // Special case: web feed that is not using Feed Query requests go to
     // WebFeedListContentsDiscoverApi.
     network.SendApiRequest<WebFeedListContentsDiscoverApi>(
-        std::move(request), gaia,
+        std::move(request), account_info,
         base::BindOnce(&LoadStreamTask::QueryApiRequestComplete, GetWeakPtr()));
   } else if (options_.stream_type.IsForYou() &&
              base::FeatureList::IsEnabled(kDiscoFeedEndpoint)) {
@@ -275,13 +275,13 @@
       case LoadType::kInitialLoad:
       case LoadType::kManualRefresh:
         network.SendApiRequest<QueryInteractiveFeedDiscoverApi>(
-            request, gaia,
+            request, account_info,
             base::BindOnce(&LoadStreamTask::QueryApiRequestComplete,
                            GetWeakPtr()));
         break;
       case LoadType::kBackgroundRefresh:
         network.SendApiRequest<QueryBackgroundFeedDiscoverApi>(
-            request, gaia,
+            request, account_info,
             base::BindOnce(&LoadStreamTask::QueryApiRequestComplete,
                            GetWeakPtr()));
         break;
@@ -292,7 +292,7 @@
   } else {
     // Other requests use GWS.
     network.SendQueryRequest(
-        NetworkRequestType::kFeedQuery, request, gaia,
+        NetworkRequestType::kFeedQuery, request, account_info,
         base::BindOnce(&LoadStreamTask::QueryRequestComplete, GetWeakPtr()));
   }
 }
@@ -342,7 +342,7 @@
   RefreshResponseData response_data =
       stream_.GetWireResponseTranslator().TranslateWireResponse(
           *response_body, StreamModelUpdateRequest::Source::kNetworkUpdate,
-          response_info.was_signed_in, base::Time::Now());
+          response_info.account_info, base::Time::Now());
   server_send_timestamp_ns_ =
       response_data.server_request_received_timestamp_ns;
   server_receive_timestamp_ns_ =
@@ -363,11 +363,12 @@
                                          *response_data.model_update_request),
                                      base::DoNothing());
 
-  fetched_content_has_notice_card_ =
+  const bool fetched_content_has_notice_card =
       response_data.model_update_request->stream_data
           .privacy_notice_fulfilled();
-
-  MetricsReporter::NoticeCardFulfilled(*fetched_content_has_notice_card_);
+  feed::prefs::SetLastFetchHadNoticeCard(*stream_.profile_prefs(),
+                                         fetched_content_has_notice_card);
+  MetricsReporter::NoticeCardFulfilled(fetched_content_has_notice_card);
 
   auto updated_metadata = stream_.GetMetadata();
   SetLastFetchTime(updated_metadata, options_.stream_type, base::Time::Now());
@@ -424,7 +425,6 @@
   result.network_response_info = network_response_info_;
   result.loaded_new_content_from_network = loaded_new_content_from_network_;
   result.latencies = std::move(latencies_);
-  result.fetched_content_has_notice_card = fetched_content_has_notice_card_;
   result.upload_actions_result = std::move(upload_actions_result_);
   result.experiments = experiments_;
   result.launch_result = launch_result.launch_result;
diff --git a/components/feed/core/v2/tasks/load_stream_task.h b/components/feed/core/v2/tasks/load_stream_task.h
index 162444f..5d0abe5 100644
--- a/components/feed/core/v2/tasks/load_stream_task.h
+++ b/components/feed/core/v2/tasks/load_stream_task.h
@@ -68,7 +68,6 @@
     absl::optional<NetworkResponseInfo> network_response_info;
     bool loaded_new_content_from_network = false;
     std::unique_ptr<LoadLatencyTimes> latencies;
-    absl::optional<bool> fetched_content_has_notice_card;
 
     // Result of the upload actions task.
     std::unique_ptr<UploadActionsTask::Result> upload_actions_result;
@@ -134,7 +133,6 @@
   base::OnceCallback<void(Result)> done_callback_;
   std::unique_ptr<UploadActionsTask> upload_actions_task_;
   std::unique_ptr<UploadActionsTask::Result> upload_actions_result_;
-  absl::optional<bool> fetched_content_has_notice_card_;
   LaunchReliabilityLogger& launch_reliability_logger_;
   int64_t server_receive_timestamp_ns_ = 0l;
   int64_t server_send_timestamp_ns_ = 0l;
diff --git a/components/feed/core/v2/tasks/prefetch_images_task.cc b/components/feed/core/v2/tasks/prefetch_images_task.cc
index ac6ab91..7ee34ac2 100644
--- a/components/feed/core/v2/tasks/prefetch_images_task.cc
+++ b/components/feed/core/v2/tasks/prefetch_images_task.cc
@@ -72,7 +72,7 @@
   // surfaces to update. For this reason, we're not going to retain the loaded
   // model for use outside of this task.
   StreamModel::Context model_context;
-  StreamModel model(&model_context);
+  StreamModel model(&model_context, LoggingParameters{});
   model.Update(std::move(result.update_request));
   PrefetchImagesFromModel(model);
 }
diff --git a/components/feed/core/v2/tasks/upload_actions_task.cc b/components/feed/core/v2/tasks/upload_actions_task.cc
index 980073e..c567368c8 100644
--- a/components/feed/core/v2/tasks/upload_actions_task.cc
+++ b/components/feed/core/v2/tasks/upload_actions_task.cc
@@ -13,14 +13,17 @@
 #include "components/feed/core/proto/v2/wire/upload_actions_request.pb.h"
 #include "components/feed/core/proto/v2/wire/upload_actions_response.pb.h"
 #include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/enums.h"
 #include "components/feed/core/v2/feed_network.h"
 #include "components/feed/core/v2/feed_store.h"
 #include "components/feed/core/v2/feed_stream.h"
 #include "components/feed/core/v2/feedstore_util.h"
+#include "components/feed/core/v2/ios_shared_prefs.h"
 #include "components/feed/core/v2/launch_reliability_logger.h"
 #include "components/feed/core/v2/metrics_reporter.h"
 #include "components/feed/core/v2/proto_util.h"
 #include "components/feed/core/v2/request_throttler.h"
+#include "components/feed/core/v2/types.h"
 
 namespace feed {
 using feedstore::StoredAction;
@@ -107,20 +110,28 @@
 };
 
 UploadActionsTask::UploadActionsTask(
-    feedwire::FeedAction action,
-    bool upload_now,
     FeedStream* stream,
     base::OnceCallback<void(UploadActionsTask::Result)> callback)
-    : stream_(*stream),
-      upload_now_(upload_now),
-      wire_action_(std::move(action)),
-      callback_(std::move(callback)) {
+    : stream_(*stream), callback_(std::move(callback)) {
+  account_info_ = stream_.GetAccountInfo();
+}
+
+UploadActionsTask::UploadActionsTask(
+    feedwire::FeedAction action,
+    bool upload_now,
+    const LoggingParameters& logging_parameters,
+    FeedStream* stream,
+    base::OnceCallback<void(UploadActionsTask::Result)> callback)
+    : UploadActionsTask(stream, std::move(callback)) {
+  upload_now_ = upload_now;
+  logging_parameters_ = logging_parameters;
+  wire_action_ = std::move(action);
+
   auto* client_data = wire_action_->mutable_client_data();
   client_data->set_timestamp_seconds(
       (base::Time::Now() - base::Time::UnixEpoch()).InSeconds());
   client_data->set_action_surface(
       feedwire::ActionSurface::ANDROID_CHROME_NEW_TAB);
-  gaia_ = stream_.GetSyncSignedInGaia();
 }
 
 UploadActionsTask::UploadActionsTask(
@@ -128,22 +139,18 @@
     FeedStream* stream,
     LaunchReliabilityLogger* launch_reliability_logger,
     base::OnceCallback<void(UploadActionsTask::Result)> callback)
-    : stream_(*stream),
-      pending_actions_(std::move(pending_actions)),
-      callback_(std::move(callback)),
-      launch_reliability_logger_(launch_reliability_logger) {
-  gaia_ = stream_.GetSyncSignedInGaia();
+    : UploadActionsTask(stream, std::move(callback)) {
+  pending_actions_ = std::move(pending_actions);
+  launch_reliability_logger_ = launch_reliability_logger;
 }
 
 UploadActionsTask::UploadActionsTask(
     FeedStream* stream,
     LaunchReliabilityLogger* launch_reliability_logger,
     base::OnceCallback<void(UploadActionsTask::Result)> callback)
-    : stream_(*stream),
-      read_pending_actions_(true),
-      callback_(std::move(callback)),
-      launch_reliability_logger_(launch_reliability_logger) {
-  gaia_ = stream_.GetSyncSignedInGaia();
+    : UploadActionsTask(stream, std::move(callback)) {
+  read_pending_actions_ = true;
+  launch_reliability_logger_ = launch_reliability_logger;
 }
 
 UploadActionsTask::~UploadActionsTask() = default;
@@ -159,7 +166,21 @@
   // From constructor 1: If there is an action to store, store it and maybe try
   // to upload all pending actions.
   if (wire_action_) {
+    // Abort if we shouldn't be sending or storing this action.
+    if (logging_parameters_.email.empty()) {
+      Done(UploadActionsStatus::kAbortUploadForSignedOutUser);
+      return;
+    }
+    // Are logging parameters associated with a different account?
+    if (logging_parameters_.email != account_info_.email
+        // Is the datastore associated with a different account?
+        || stream_.GetMetadata().gaia() != account_info_.gaia) {
+      Done(UploadActionsStatus::kAbortUploadForWrongUser);
+      return;
+    }
+
     StoredAction action;
+
     feedstore::Metadata metadata = stream_.GetMetadata();
     int32_t action_id = feedstore::GetNextActionId(metadata).GetUnsafeValue();
     stream_.SetMetadata(std::move(metadata));
@@ -196,11 +217,6 @@
     return;
   }
 
-  if (!stream_.CanUploadActions()) {
-    Done(UploadActionsStatus::kAbortUploadBecauseDisabled);
-    return;
-  }
-
   // If the new action was stored and upload_now was set, load all pending
   // actions and try to upload.
   ReadActions();
@@ -229,14 +245,12 @@
     return;
   }
   // Can't upload actions for another user, so abort.
-  if (stream_.GetSyncSignedInGaia() != gaia_) {
+  if (stream_.GetAccountInfo() != account_info_ ||
+      // Is the datastore associated with a different account?
+      stream_.GetMetadata().gaia() != account_info_.gaia) {
     Done(UploadActionsStatus::kAbortUploadForWrongUser);
     return;
   }
-  if (!stream_.CanUploadActions()) {
-    Done(UploadActionsStatus::kAbortUploadBecauseDisabled);
-    return;
-  }
   UpdateAndUploadNextBatch();
 }
 
@@ -284,7 +298,7 @@
   }
 
   stream_.GetNetwork().SendApiRequest<UploadActionsDiscoverApi>(
-      *request, gaia_,
+      *request, account_info_,
       base::BindOnce(&UploadActionsTask::OnUploadFinished,
                      weak_ptr_factory_.GetWeakPtr(), std::move(batch)));
 }
diff --git a/components/feed/core/v2/tasks/upload_actions_task.h b/components/feed/core/v2/tasks/upload_actions_task.h
index ca288cd..0c6ee271 100644
--- a/components/feed/core/v2/tasks/upload_actions_task.h
+++ b/components/feed/core/v2/tasks/upload_actions_task.h
@@ -18,6 +18,7 @@
 #include "components/feed/core/v2/feed_network.h"
 #include "components/feed/core/v2/feed_store.h"
 #include "components/feed/core/v2/launch_reliability_logger.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
 #include "components/feed/core/v2/types.h"
 #include "components/offline_pages/task/task.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -61,6 +62,7 @@
   // string if no token was received).
   UploadActionsTask(feedwire::FeedAction action,
                     bool upload_now,
+                    const LoggingParameters& logging_parameters,
                     FeedStream* stream,
                     base::OnceCallback<void(Result)> callback);
   // Upload |pending_actions| and update the store. Note: |pending_actions|
@@ -80,6 +82,9 @@
   UploadActionsTask& operator=(const UploadActionsTask&) = delete;
 
  private:
+  explicit UploadActionsTask(
+      FeedStream* stream,
+      base::OnceCallback<void(UploadActionsTask::Result)> callback);
   class Batch;
 
   void Run() override;
@@ -103,6 +108,7 @@
   FeedStream& stream_;
   bool upload_now_ = false;
   bool read_pending_actions_ = false;
+  LoggingParameters logging_parameters_;
   // Pending action to be stored.
   absl::optional<feedwire::FeedAction> wire_action_;
 
@@ -120,9 +126,7 @@
   // Number of stale actions.
   size_t stale_count_ = 0;
   absl::optional<NetworkResponseInfo> last_network_response_info_;
-
-  std::string gaia_;
-
+  AccountInfo account_info_;
   raw_ptr<LaunchReliabilityLogger> launch_reliability_logger_ = nullptr;
   NetworkRequestId last_network_request_id_;
 
diff --git a/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc b/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc
index 47b4649..83052447 100644
--- a/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc
+++ b/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc
@@ -34,7 +34,7 @@
 void WaitForStoreInitializeTask::ReadStartupDataDone(
     FeedStore::StartupData startup_data) {
   if (startup_data.metadata &&
-      startup_data.metadata->gaia() != stream_.GetSyncSignedInGaia()) {
+      startup_data.metadata->gaia() != stream_.GetAccountInfo().gaia) {
     store_.ClearAll(base::BindOnce(&WaitForStoreInitializeTask::ClearAllDone,
                                    base::Unretained(this)));
     return;
@@ -57,7 +57,7 @@
   if (metadata.stream_schema_version() != 1) {
     result_.startup_data.stream_data.clear();
     if (metadata.gaia().empty()) {
-      metadata.set_gaia(stream_.GetSyncSignedInGaia());
+      metadata.set_gaia(stream_.GetAccountInfo().gaia);
     }
     store_.UpgradeFromStreamSchemaV0(
         std::move(metadata),
diff --git a/components/feed/core/v2/test/stream_builder.cc b/components/feed/core/v2/test/stream_builder.cc
index cac47b6..21a9356 100644
--- a/components/feed/core/v2/test/stream_builder.cc
+++ b/components/feed/core/v2/test/stream_builder.cc
@@ -17,6 +17,9 @@
 namespace feed {
 
 base::Time kTestTimeEpoch = base::Time::UnixEpoch();
+AccountInfo TestAccountInfo() {
+  return {"gaia", "user@foo"};
+}
 
 ContentId MakeContentId(ContentId::Type type,
                         std::string content_domain,
@@ -238,6 +241,10 @@
       MakeSharedStateId(first_cluster_id);
   initial_update->stream_data.set_next_page_token("page-2");
   initial_update->stream_data.set_signed_in(signed_in);
+  if (signed_in) {
+    initial_update->stream_data.set_email(account_info.email);
+    initial_update->stream_data.set_gaia(account_info.gaia);
+  }
   initial_update->stream_data.set_logging_enabled(logging_enabled);
   initial_update->stream_data.set_privacy_notice_fulfilled(
       privacy_notice_fulfilled);
@@ -277,6 +284,10 @@
   initial_update->stream_data.set_next_page_token(
       "page-" + base::NumberToString(page_number + 1));
   initial_update->stream_data.set_signed_in(signed_in);
+  if (signed_in) {
+    initial_update->stream_data.set_email(account_info.email);
+    initial_update->stream_data.set_gaia(account_info.gaia);
+  }
   initial_update->stream_data.set_logging_enabled(logging_enabled);
   initial_update->stream_data.set_privacy_notice_fulfilled(
       privacy_notice_fulfilled);
diff --git a/components/feed/core/v2/test/stream_builder.h b/components/feed/core/v2/test/stream_builder.h
index 06b93b4..55c3f289 100644
--- a/components/feed/core/v2/test/stream_builder.h
+++ b/components/feed/core/v2/test/stream_builder.h
@@ -14,6 +14,7 @@
 #include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
 #include "components/feed/core/v2/proto_util.h"
 #include "components/feed/core/v2/protocol_translator.h"
+#include "components/feed/core/v2/public/types.h"
 #include "components/feed/core/v2/types.h"
 
 // Functions that help build a feedstore::StreamStructure for testing.
@@ -23,6 +24,7 @@
 extern base::Time kTestTimeEpoch;
 constexpr int64_t kFollowerCount = 123;
 
+AccountInfo TestAccountInfo();
 ContentId MakeContentId(ContentId::Type type,
                         std::string content_domain,
                         int id_number);
@@ -59,6 +61,7 @@
 struct StreamModelUpdateRequestGenerator {
   base::Time last_added_time = kTestTimeEpoch;
   bool signed_in = true;
+  AccountInfo account_info = TestAccountInfo();
   bool logging_enabled = true;
   bool privacy_notice_fulfilled = false;
   int event_id_number = 123;
diff --git a/components/feed/core/v2/types.cc b/components/feed/core/v2/types.cc
index 9194128..5ba085d 100644
--- a/components/feed/core/v2/types.cc
+++ b/components/feed/core/v2/types.cc
@@ -13,7 +13,6 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
-#include "components/feed/core/proto/v2/ui.pb.h"
 #include "components/feed/core/v2/public/types.h"
 
 // Note: This file contains implementation for both types.h and public/types.h.
@@ -224,37 +223,4 @@
 LaunchResult::~LaunchResult() = default;
 LaunchResult& LaunchResult::operator=(const LaunchResult& other) = default;
 
-LoggingParameters::LoggingParameters() = default;
-LoggingParameters::~LoggingParameters() = default;
-LoggingParameters::LoggingParameters(const LoggingParameters&) = default;
-LoggingParameters::LoggingParameters(LoggingParameters&&) = default;
-LoggingParameters& LoggingParameters::operator=(const LoggingParameters&) =
-    default;
-
-bool LoggingParameters::operator==(const LoggingParameters& rhs) const {
-  return std::tie(email, client_instance_id, logging_enabled,
-                  view_actions_enabled) ==
-         std::tie(rhs.email, rhs.client_instance_id, logging_enabled,
-                  view_actions_enabled);
-}
-
-LoggingParameters FromProto(const feedui::LoggingParameters& proto) {
-  LoggingParameters result;
-  result.email = proto.email();
-  result.client_instance_id = proto.client_instance_id();
-  result.logging_enabled = proto.logging_enabled();
-  result.view_actions_enabled = proto.view_actions_enabled();
-  result.root_event_id = proto.root_event_id();
-  return result;
-}
-
-void ToProto(const LoggingParameters& logging_parameters,
-             feedui::LoggingParameters& proto) {
-  proto.set_email(logging_parameters.email);
-  proto.set_client_instance_id(logging_parameters.client_instance_id);
-  proto.set_logging_enabled(logging_parameters.logging_enabled);
-  proto.set_view_actions_enabled(logging_parameters.view_actions_enabled);
-  proto.set_root_event_id(logging_parameters.root_event_id);
-}
-
 }  // namespace feed
diff --git a/components/feed/core/v2/types.h b/components/feed/core/v2/types.h
index 8aacaf6b..a853135 100644
--- a/components/feed/core/v2/types.h
+++ b/components/feed/core/v2/types.h
@@ -19,9 +19,6 @@
 #include "components/feed/core/v2/public/common_enums.h"
 #include "components/feed/core/v2/public/types.h"
 
-namespace feedui {
-class LoggingParameters;
-}
 namespace feed {
 
 // Make sure public types are included here too.
@@ -149,31 +146,6 @@
   LaunchResult& operator=(const LaunchResult& other);
 };
 
-struct LoggingParameters {
-  LoggingParameters();
-  ~LoggingParameters();
-  LoggingParameters(const LoggingParameters&);
-  LoggingParameters(LoggingParameters&&);
-  LoggingParameters& operator=(const LoggingParameters&);
-
-  // User ID, if the user is signed-in.
-  std::string email;
-  // A unique ID for this client. Used for reliability logging.
-  std::string client_instance_id;
-  // Whether attention / interaction logging is enabled.
-  bool logging_enabled = false;
-  // Whether view actions may be recorded.
-  bool view_actions_enabled = false;
-  // EventID of the first page response.
-  std::string root_event_id;
-
-  bool operator==(const LoggingParameters& rhs) const;
-};
-
-LoggingParameters FromProto(const feedui::LoggingParameters& proto);
-void ToProto(const LoggingParameters& logging_parameters,
-             feedui::LoggingParameters& proto);
-
 }  // namespace feed
 
 #endif  // COMPONENTS_FEED_CORE_V2_TYPES_H_
diff --git a/components/feed/core/v2/types_unittest.cc b/components/feed/core/v2/types_unittest.cc
index 9c8ef7e..08907c26 100644
--- a/components/feed/core/v2/types_unittest.cc
+++ b/components/feed/core/v2/types_unittest.cc
@@ -5,7 +5,6 @@
 #include "components/feed/core/v2/types.h"
 #include "base/json/json_writer.h"
 #include "base/strings/string_util.h"
-#include "components/feed/core/proto/v2/ui.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace feed {
@@ -62,34 +61,4 @@
   EXPECT_TRUE(ContentIdSet().IsEmpty());
 }
 
-TEST(Types, LoggingParametersSet_ToFromProto) {
-  LoggingParameters params;
-  params.email = "foo@bar.com";
-  params.client_instance_id = "instanceid";
-  params.logging_enabled = true;
-  params.view_actions_enabled = true;
-
-  feedui::LoggingParameters proto;
-  ToProto(params, proto);
-
-  EXPECT_EQ("foo@bar.com", proto.email());
-  EXPECT_EQ("instanceid", proto.client_instance_id());
-  EXPECT_EQ(true, proto.logging_enabled());
-  EXPECT_EQ(true, proto.view_actions_enabled());
-  EXPECT_EQ(params, FromProto(proto));
-}
-
-TEST(Types, LoggingParametersEmpty_ToFromProto) {
-  LoggingParameters params;
-
-  feedui::LoggingParameters proto;
-  ToProto(params, proto);
-
-  EXPECT_EQ("", proto.email());
-  EXPECT_EQ("", proto.client_instance_id());
-  EXPECT_EQ(false, proto.logging_enabled());
-  EXPECT_EQ(false, proto.view_actions_enabled());
-  EXPECT_EQ(params, FromProto(proto));
-}
-
 }  // namespace feed
diff --git a/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc b/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc
index 44c8cf9..d0d7518 100644
--- a/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc
+++ b/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc
@@ -38,7 +38,7 @@
   feedwire::webfeed::ListRecommendedWebFeedsRequest request;
   SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
   stream_.GetNetwork().SendApiRequest<ListRecommendedWebFeedDiscoverApi>(
-      request, stream_.GetSyncSignedInGaia(),
+      request, stream_.GetAccountInfo(),
       base::BindOnce(&FetchRecommendedWebFeedsTask::RequestComplete,
                      base::Unretained(this)));
 }
diff --git a/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc b/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc
index eac8993..c881be0 100644
--- a/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc
+++ b/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc
@@ -40,7 +40,7 @@
   feedwire::webfeed::ListWebFeedsRequest request;
   SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
   stream_.GetNetwork().SendApiRequest<ListWebFeedsDiscoverApi>(
-      request, stream_.GetSyncSignedInGaia(),
+      request, stream_.GetAccountInfo(),
       base::BindOnce(&FetchSubscribedWebFeedsTask::RequestComplete,
                      base::Unretained(this)));
 }
diff --git a/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc b/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
index 8b7370d03..823e01e2 100644
--- a/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
+++ b/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
@@ -48,7 +48,7 @@
     SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
     request.set_name(request_.web_feed_id);
     stream_.GetNetwork().SendApiRequest<FollowWebFeedDiscoverApi>(
-        request, stream_.GetSyncSignedInGaia(),
+        request, stream_.GetAccountInfo(),
         base::BindOnce(&SubscribeToWebFeedTask::RequestComplete,
                        base::Unretained(this)));
   } else {
@@ -74,7 +74,7 @@
       request.add_page_rss_uris(rss_url.spec());
     }
     stream_.GetNetwork().SendApiRequest<FollowWebFeedDiscoverApi>(
-        request, stream_.GetSyncSignedInGaia(),
+        request, stream_.GetAccountInfo(),
         base::BindOnce(&SubscribeToWebFeedTask::RequestComplete,
                        base::Unretained(this)));
   }
diff --git a/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc b/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc
index 7a4230f..005883f 100644
--- a/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc
+++ b/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc
@@ -51,7 +51,7 @@
   SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
   request.set_name(web_feed_name_);
   stream_.GetNetwork().SendApiRequest<UnfollowWebFeedDiscoverApi>(
-      request, stream_.GetSyncSignedInGaia(),
+      request, stream_.GetAccountInfo(),
       base::BindOnce(&UnsubscribeFromWebFeedTask::RequestComplete,
                      base::Unretained(this)));
 }
diff --git a/components/feed/core/v2/wire_response_translator.cc b/components/feed/core/v2/wire_response_translator.cc
index daefe46..6a418c5 100644
--- a/components/feed/core/v2/wire_response_translator.cc
+++ b/components/feed/core/v2/wire_response_translator.cc
@@ -9,10 +9,10 @@
 RefreshResponseData WireResponseTranslator::TranslateWireResponse(
     feedwire::Response response,
     StreamModelUpdateRequest::Source source,
-    bool was_signed_in_request,
+    const AccountInfo& account_info,
     base::Time current_time) const {
   return ::feed::TranslateWireResponse(std::move(response), source,
-                                       was_signed_in_request, current_time);
+                                       account_info, current_time);
 }
 
 }  // namespace feed
diff --git a/components/feed/core/v2/wire_response_translator.h b/components/feed/core/v2/wire_response_translator.h
index c4b8b99..a9a34ae 100644
--- a/components/feed/core/v2/wire_response_translator.h
+++ b/components/feed/core/v2/wire_response_translator.h
@@ -8,6 +8,7 @@
 #include "components/feed/core/v2/protocol_translator.h"
 
 namespace feed {
+struct AccountInfo;
 
 // Forwards to |feed::TranslateWireResponse()| by default. Can be overridden
 // for testing.
@@ -18,7 +19,7 @@
   virtual RefreshResponseData TranslateWireResponse(
       feedwire::Response response,
       StreamModelUpdateRequest::Source source,
-      bool was_signed_in_request,
+      const AccountInfo& account_info,
       base::Time current_time) const;
 };
 
diff --git a/components/feed/feed_feature_list.h b/components/feed/feed_feature_list.h
index 913df4f6..ccd73ba 100644
--- a/components/feed/feed_feature_list.h
+++ b/components/feed/feed_feature_list.h
@@ -27,6 +27,8 @@
 extern const base::FeatureParam<bool> kThrottleBackgroundFetches;
 extern const base::FeatureParam<bool> kOnlySetLastRefreshAttemptOnSuccess;
 
+// TODO(b/213622639): The following two features are obsolete and should be
+// removed.
 // Determines whether conditions should be reached before enabling the upload of
 // click and view actions in the feed (e.g., the user needs to view X cards).
 // For example, this is needed when the notice card is at the second position in
diff --git a/components/js_injection/browser/js_communication_host.cc b/components/js_injection/browser/js_communication_host.cc
index 9f75428..a66611e 100644
--- a/components/js_injection/browser/js_communication_host.cc
+++ b/components/js_injection/browser/js_communication_host.cc
@@ -92,7 +92,7 @@
 
   scripts_.emplace_back(script, origin_matcher, next_script_id_++);
 
-  web_contents()->ForEachFrame(base::BindRepeating(
+  web_contents()->GetMainFrame()->ForEachRenderFrameHost(base::BindRepeating(
       &JsCommunicationHost::NotifyFrameForAddDocumentStartJavaScript,
       base::Unretained(this), &*scripts_.rbegin()));
   result.script_id = scripts_.rbegin()->script_id_;
@@ -103,9 +103,10 @@
   for (auto it = scripts_.begin(); it != scripts_.end(); ++it) {
     if (it->script_id_ == script_id) {
       scripts_.erase(it);
-      web_contents()->ForEachFrame(base::BindRepeating(
-          &JsCommunicationHost::NotifyFrameForRemoveDocumentStartJavaScript,
-          base::Unretained(this), script_id));
+      web_contents()->GetMainFrame()->ForEachRenderFrameHost(
+          base::BindRepeating(
+              &JsCommunicationHost::NotifyFrameForRemoveDocumentStartJavaScript,
+              base::Unretained(this), script_id));
       return true;
     }
   }
@@ -131,7 +132,7 @@
   js_objects_.push_back(std::make_unique<JsObject>(
       js_object_name, origin_matcher, std::move(factory)));
 
-  web_contents()->ForEachFrame(base::BindRepeating(
+  web_contents()->GetMainFrame()->ForEachRenderFrameHost(base::BindRepeating(
       &JsCommunicationHost::NotifyFrameForWebMessageListener,
       base::Unretained(this)));
   return std::u16string();
@@ -143,9 +144,10 @@
        ++iterator) {
     if ((*iterator)->name == js_object_name) {
       js_objects_.erase(iterator);
-      web_contents()->ForEachFrame(base::BindRepeating(
-          &JsCommunicationHost::NotifyFrameForWebMessageListener,
-          base::Unretained(this)));
+      web_contents()->GetMainFrame()->ForEachRenderFrameHost(
+          base::BindRepeating(
+              &JsCommunicationHost::NotifyFrameForWebMessageListener,
+              base::Unretained(this)));
       break;
     }
   }
diff --git a/components/omnibox/bug-triage.md b/components/omnibox/bug-triage.md
index 5b42970..de02dfb 100644
--- a/components/omnibox/bug-triage.md
+++ b/components/omnibox/bug-triage.md
@@ -178,6 +178,7 @@
 | UI>Browser>Omnibox>SecurityIndicators | Secure/insecure icons; triaged by another team. |
 | UI>Browser>Omnibox>TabToSearch | Custom search engines, omnibox extensions, etc. (including adding, triggering, ranking, etc. for them). |
 | UI>Browser>Omnibox>ZeroSuggest | Suggestions displayed on omnibox focus (both contextual and non-contextual). |
+| UI>Browser>Omnibox>NTPRealbox | Suggestions displayed in the searchbox on the New Tab Page. |
 
 If the bug is extremely low priority, set the **NextAction field** to
 **01/07/2021** and mention that we will "reassess" the bug next year.  This
@@ -238,7 +239,7 @@
 especially the split by channel, split by platform, split by milestone, and
 split by version features.  Some tips on how to investigate using the timeline
 dashboard:
- 
+
 * If the regression is on Dev, see if you can spot it on Canary.  That can
   usually indicate a narrow regression range.  This can usually be done unless
   the histogram is too noisy.
diff --git a/components/reading_list/features/reading_list_switches.cc b/components/reading_list/features/reading_list_switches.cc
index fa44390..1c16bfc5 100644
--- a/components/reading_list/features/reading_list_switches.cc
+++ b/components/reading_list/features/reading_list_switches.cc
@@ -20,12 +20,11 @@
 namespace switches {
 
 // Allow users to save tabs for later. Enables a new button and menu for
-// accessing tabs saved for later. https://crbug.com/1109316
-#if defined(OS_ANDROID)
-const base::Feature kReadLater{"ReadLater", base::FEATURE_DISABLED_BY_DEFAULT};
-#else
+// accessing tabs saved for later.
+// android: https://crbug.com/1123087
+// desktop: https://crbug.com/1109316
+// ios: https://crbug.com/577659
 const base::Feature kReadLater{"ReadLater", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
 
 bool IsReadingListEnabled() {
 #if defined(OS_IOS)
diff --git a/components/services/unzip/unzipper_impl.cc b/components/services/unzip/unzipper_impl.cc
index b710ab8..54ecfd0 100644
--- a/components/services/unzip/unzipper_impl.cc
+++ b/components/services/unzip/unzipper_impl.cc
@@ -34,6 +34,7 @@
   bool PrepareOutput() override { return false; }
   bool WriteBytes(const char* data, int num_bytes) override { return false; }
   void SetTimeModified(const base::Time& time) override {}
+  void SetPosixFilePermissions(int mode) override {}
 };
 
 std::string PathToMojoString(const base::FilePath& path) {
diff --git a/components/shared_highlighting/core/common/shared_highlighting_features.cc b/components/shared_highlighting/core/common/shared_highlighting_features.cc
index 13ee4e1..abbe08a 100644
--- a/components/shared_highlighting/core/common/shared_highlighting_features.cc
+++ b/components/shared_highlighting/core/common/shared_highlighting_features.cc
@@ -14,7 +14,7 @@
     &kPreemptiveLinkToTextGeneration, "TimeoutLengthMs", 500};
 
 const base::Feature kSharedHighlightingV2{"SharedHighlightingV2",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
+                                          base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kSharedHighlightingAmp{"SharedHighlightingAmp",
                                            base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/sync/base/BUILD.gn b/components/sync/base/BUILD.gn
index a95b503..354c497 100644
--- a/components/sync/base/BUILD.gn
+++ b/components/sync/base/BUILD.gn
@@ -25,8 +25,6 @@
     "invalidation_adapter.h",
     "invalidation_helper.cc",
     "invalidation_helper.h",
-    "invalidation_interface.cc",
-    "invalidation_interface.h",
     "legacy_directory_deletion.cc",
     "legacy_directory_deletion.h",
     "logging.cc",
@@ -47,6 +45,8 @@
     "stop_source.h",
     "sync_base_switches.cc",
     "sync_base_switches.h",
+    "sync_invalidation.cc",
+    "sync_invalidation.h",
     "sync_mode.h",
     "sync_prefs.cc",
     "sync_prefs.h",
diff --git a/components/sync/base/invalidation_adapter.h b/components/sync/base/invalidation_adapter.h
index c18881f..7e6a5e2 100644
--- a/components/sync/base/invalidation_adapter.h
+++ b/components/sync/base/invalidation_adapter.h
@@ -10,17 +10,17 @@
 #include <string>
 
 #include "components/invalidation/public/invalidation.h"
-#include "components/sync/base/invalidation_interface.h"
+#include "components/sync/base/sync_invalidation.h"
 
 namespace syncer {
 
-// Wraps a Invalidation in the InvalidationInterface.
-class InvalidationAdapter : public InvalidationInterface {
+// Wraps a Invalidation in the SyncInvalidation interface.
+class InvalidationAdapter : public SyncInvalidation {
  public:
   explicit InvalidationAdapter(const invalidation::Invalidation& invalidation);
   ~InvalidationAdapter() override;
 
-  // Implementation of InvalidationInterface.
+  // Implementation of SyncInvalidation.
   bool IsUnknownVersion() const override;
   const std::string& GetPayload() const override;
   int64_t GetVersion() const override;
diff --git a/components/sync/base/invalidation_interface.cc b/components/sync/base/invalidation_interface.cc
deleted file mode 100644
index 67f5876..0000000
--- a/components/sync/base/invalidation_interface.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/sync/base/invalidation_interface.h"
-
-namespace syncer {
-
-bool InvalidationInterface::LessThanByVersion(const InvalidationInterface& a,
-                                              const InvalidationInterface& b) {
-  if (a.IsUnknownVersion() && !b.IsUnknownVersion())
-    return true;
-
-  if (!a.IsUnknownVersion() && b.IsUnknownVersion())
-    return false;
-
-  if (a.IsUnknownVersion() && b.IsUnknownVersion())
-    return false;
-
-  return a.GetVersion() < b.GetVersion();
-}
-
-InvalidationInterface::InvalidationInterface() = default;
-
-InvalidationInterface::~InvalidationInterface() = default;
-
-}  // namespace syncer
diff --git a/components/sync/base/sync_invalidation.cc b/components/sync/base/sync_invalidation.cc
new file mode 100644
index 0000000..47496e9
--- /dev/null
+++ b/components/sync/base/sync_invalidation.cc
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync/base/sync_invalidation.h"
+
+namespace syncer {
+
+bool SyncInvalidation::LessThanByVersion(const SyncInvalidation& a,
+                                         const SyncInvalidation& b) {
+  if (a.IsUnknownVersion() && !b.IsUnknownVersion())
+    return true;
+
+  if (!a.IsUnknownVersion() && b.IsUnknownVersion())
+    return false;
+
+  if (a.IsUnknownVersion() && b.IsUnknownVersion())
+    return false;
+
+  return a.GetVersion() < b.GetVersion();
+}
+
+SyncInvalidation::SyncInvalidation() = default;
+
+SyncInvalidation::~SyncInvalidation() = default;
+
+}  // namespace syncer
diff --git a/components/sync/base/invalidation_interface.h b/components/sync/base/sync_invalidation.h
similarity index 78%
rename from components/sync/base/invalidation_interface.h
rename to components/sync/base/sync_invalidation.h
index 8481749..6ff7ecb 100644
--- a/components/sync/base/invalidation_interface.h
+++ b/components/sync/base/sync_invalidation.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SYNC_BASE_INVALIDATION_INTERFACE_H_
-#define COMPONENTS_SYNC_BASE_INVALIDATION_INTERFACE_H_
+#ifndef COMPONENTS_SYNC_BASE_SYNC_INVALIDATION_H_
+#define COMPONENTS_SYNC_BASE_SYNC_INVALIDATION_H_
 
 #include <stdint.h>
 
@@ -13,14 +13,14 @@
 
 // An interface that wraps sync's interactions with the component that provides
 // it with invalidations.
-class InvalidationInterface {
+class SyncInvalidation {
  public:
   // Orders invalidations based on version number and IsUnknownVersion().
-  static bool LessThanByVersion(const InvalidationInterface& a,
-                                const InvalidationInterface& b);
+  static bool LessThanByVersion(const SyncInvalidation& a,
+                                const SyncInvalidation& b);
 
-  InvalidationInterface();
-  virtual ~InvalidationInterface();
+  SyncInvalidation();
+  virtual ~SyncInvalidation();
 
   // Returns true if this is an 'unknown version' invalidation.
   // Such invalidations have no valid payload or version number.
@@ -51,4 +51,4 @@
 
 }  // namespace syncer
 
-#endif  // COMPONENTS_SYNC_BASE_INVALIDATION_INTERFACE_H_
+#endif  // COMPONENTS_SYNC_BASE_SYNC_INVALIDATION_H_
diff --git a/components/sync/driver/glue/sync_engine_backend.cc b/components/sync/driver/glue/sync_engine_backend.cc
index 4754cf8..6a629747 100644
--- a/components/sync/driver/glue/sync_engine_backend.cc
+++ b/components/sync/driver/glue/sync_engine_backend.cc
@@ -47,7 +47,7 @@
 const base::FilePath::CharType kNigoriStorageFilename[] =
     FILE_PATH_LITERAL("Nigori.bin");
 
-class SyncInvalidationAdapter : public InvalidationInterface {
+class SyncInvalidationAdapter : public SyncInvalidation {
  public:
   explicit SyncInvalidationAdapter(const std::string& payload)
       : payload_(payload) {}
@@ -177,7 +177,7 @@
       for (invalidation::Invalidation invalidation : invalidation_set) {
         RecordRedundantInvalidationsMetric(invalidation, type);
 
-        std::unique_ptr<InvalidationInterface> inv_adapter(
+        std::unique_ptr<SyncInvalidation> inv_adapter(
             new InvalidationAdapter(invalidation));
         sync_manager_->OnIncomingInvalidation(type, std::move(inv_adapter));
         if (!invalidation.is_unknown_version())
@@ -475,7 +475,7 @@
     }
 
     // TODO(crbug.com/1119798): Use only enabled data types.
-    std::unique_ptr<InvalidationInterface> inv_adapter =
+    std::unique_ptr<SyncInvalidation> inv_adapter =
         std::make_unique<SyncInvalidationAdapter>(payload_message.hint());
     sync_manager_->OnIncomingInvalidation(model_type, std::move(inv_adapter));
   }
diff --git a/components/sync/engine/cycle/data_type_tracker.cc b/components/sync/engine/cycle/data_type_tracker.cc
index 6dc8a5143..f0e381b 100644
--- a/components/sync/engine/cycle/data_type_tracker.cc
+++ b/components/sync/engine/cycle/data_type_tracker.cc
@@ -118,7 +118,7 @@
 }
 
 void DataTypeTracker::RecordRemoteInvalidation(
-    std::unique_ptr<InvalidationInterface> incoming) {
+    std::unique_ptr<SyncInvalidation> incoming) {
   DCHECK(incoming);
 
   // Merge the incoming invalidation into our list of pending invalidations.
@@ -141,13 +141,13 @@
 
   // Find the lower bound.
   while (it != pending_invalidations_.end() &&
-         InvalidationInterface::LessThanByVersion(**it, *incoming)) {
+         SyncInvalidation::LessThanByVersion(**it, *incoming)) {
     it++;
   }
 
   if (it != pending_invalidations_.end() &&
-      !InvalidationInterface::LessThanByVersion(*incoming, **it) &&
-      !InvalidationInterface::LessThanByVersion(**it, *incoming)) {
+      !SyncInvalidation::LessThanByVersion(*incoming, **it) &&
+      !SyncInvalidation::LessThanByVersion(**it, *incoming)) {
     // Incoming overlaps with existing.  Either both are unknown versions
     // (likely) or these two have the same version number (very unlikely).
     // Acknowledge and overwrite existing.
@@ -200,7 +200,7 @@
   // crash before writing all our state, we should wait until the results of
   // this sync cycle have been written to disk before updating the invalidations
   // state.  See crbug.com/324996.
-  for (const std::unique_ptr<InvalidationInterface>& pending_invalidation :
+  for (const std::unique_ptr<SyncInvalidation>& pending_invalidation :
        pending_invalidations_) {
     pending_invalidation->Acknowledge();
   }
@@ -293,7 +293,7 @@
   // Fill the list of payloads, if applicable.  The payloads must be ordered
   // oldest to newest, so we insert them in the same order as we've been storing
   // them internally.
-  for (const std::unique_ptr<InvalidationInterface>& pending_invalidation :
+  for (const std::unique_ptr<SyncInvalidation>& pending_invalidation :
        pending_invalidations_) {
     if (!pending_invalidation->IsUnknownVersion()) {
       msg->add_notification_hint(pending_invalidation->GetPayload());
diff --git a/components/sync/engine/cycle/data_type_tracker.h b/components/sync/engine/cycle/data_type_tracker.h
index f59bdf3..4fbe309 100644
--- a/components/sync/engine/cycle/data_type_tracker.h
+++ b/components/sync/engine/cycle/data_type_tracker.h
@@ -11,8 +11,8 @@
 #include <vector>
 
 #include "base/time/time.h"
-#include "components/sync/base/invalidation_interface.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/base/sync_invalidation.h"
 
 namespace sync_pb {
 class DataTypeProgressMarker;
@@ -21,7 +21,7 @@
 
 namespace syncer {
 
-class InvalidationInterface;
+class SyncInvalidation;
 
 struct WaitInterval {
   enum class BlockingMode {
@@ -64,8 +64,7 @@
   void RecordLocalRefreshRequest();
 
   // Tracks that we received invalidation notifications for this type.
-  void RecordRemoteInvalidation(
-      std::unique_ptr<InvalidationInterface> incoming);
+  void RecordRemoteInvalidation(std::unique_ptr<SyncInvalidation> incoming);
 
   // Takes note that initial sync is pending for this type.
   void RecordInitialSyncRequired();
@@ -177,7 +176,7 @@
   // drop_tracker_.IsRecoveringFromDropEvent() and server_payload_overflow_.
   //
   // This list takes ownership of its contents.
-  std::vector<std::unique_ptr<InvalidationInterface>> pending_invalidations_;
+  std::vector<std::unique_ptr<SyncInvalidation>> pending_invalidations_;
 
   size_t payload_buffer_size_;
 
@@ -197,7 +196,7 @@
   std::unique_ptr<WaitInterval> wait_interval_;
 
   // A helper to keep track invalidations we dropped due to overflow.
-  std::unique_ptr<InvalidationInterface> last_dropped_invalidation_;
+  std::unique_ptr<SyncInvalidation> last_dropped_invalidation_;
 
   // The amount of time to delay a sync cycle by when a local change for this
   // type occurs.
diff --git a/components/sync/engine/cycle/nudge_tracker.cc b/components/sync/engine/cycle/nudge_tracker.cc
index 330b2855..6147f2c 100644
--- a/components/sync/engine/cycle/nudge_tracker.cc
+++ b/components/sync/engine/cycle/nudge_tracker.cc
@@ -117,7 +117,7 @@
 
 base::TimeDelta NudgeTracker::RecordRemoteInvalidation(
     ModelType type,
-    std::unique_ptr<InvalidationInterface> invalidation) {
+    std::unique_ptr<SyncInvalidation> invalidation) {
   // Forward the invalidations to the proper recipient.
   TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(type);
   DCHECK(tracker_it != type_trackers_.end());
diff --git a/components/sync/engine/cycle/nudge_tracker.h b/components/sync/engine/cycle/nudge_tracker.h
index 925f72b..02635ef 100644
--- a/components/sync/engine/cycle/nudge_tracker.h
+++ b/components/sync/engine/cycle/nudge_tracker.h
@@ -13,8 +13,8 @@
 
 #include "base/compiler_specific.h"
 #include "base/time/time.h"
-#include "components/sync/base/invalidation_interface.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/base/sync_invalidation.h"
 #include "components/sync/engine/cycle/data_type_tracker.h"
 #include "components/sync/protocol/sync_enums.pb.h"
 
@@ -72,7 +72,7 @@
   // Returns the nudge delay for a remote invalidation.
   base::TimeDelta RecordRemoteInvalidation(
       ModelType type,
-      std::unique_ptr<InvalidationInterface> invalidation);
+      std::unique_ptr<SyncInvalidation> invalidation);
 
   // Take note that an initial sync is pending for this type.
   void RecordInitialSyncRequired(ModelType type);
diff --git a/components/sync/engine/cycle/nudge_tracker_unittest.cc b/components/sync/engine/cycle/nudge_tracker_unittest.cc
index ad45d72..6d5d506 100644
--- a/components/sync/engine/cycle/nudge_tracker_unittest.cc
+++ b/components/sync/engine/cycle/nudge_tracker_unittest.cc
@@ -68,14 +68,13 @@
     nudge_tracker_.RecordSuccessfulSyncCycle({});
   }
 
-  std::unique_ptr<InvalidationInterface> BuildInvalidation(
+  std::unique_ptr<SyncInvalidation> BuildInvalidation(
       int64_t version,
       const std::string& payload) {
     return MockInvalidation::Build(version, payload);
   }
 
-  static std::unique_ptr<InvalidationInterface>
-  BuildUnknownVersionInvalidation() {
+  static std::unique_ptr<SyncInvalidation> BuildUnknownVersionInvalidation() {
     return MockInvalidation::BuildUnknownVersion();
   }
 
diff --git a/components/sync/engine/get_updates_processor_unittest.cc b/components/sync/engine/get_updates_processor_unittest.cc
index ef85734d..b4dc4a99 100644
--- a/components/sync/engine/get_updates_processor_unittest.cc
+++ b/components/sync/engine/get_updates_processor_unittest.cc
@@ -28,7 +28,7 @@
 
 namespace {
 
-std::unique_ptr<InvalidationInterface> BuildInvalidation(
+std::unique_ptr<SyncInvalidation> BuildInvalidation(
     int64_t version,
     const std::string& payload) {
   return MockInvalidation::Build(version, payload);
diff --git a/components/sync/engine/sync_manager.h b/components/sync/engine/sync_manager.h
index a06b277..941b5ec 100644
--- a/components/sync/engine/sync_manager.h
+++ b/components/sync/engine/sync_manager.h
@@ -17,8 +17,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/task/task_runner.h"
 #include "base/threading/thread_checker.h"
-#include "components/sync/base/invalidation_interface.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/base/sync_invalidation.h"
 #include "components/sync/base/weak_handle.h"
 #include "components/sync/engine/active_devices_invalidation_info.h"
 #include "components/sync/engine/configure_reason.h"
@@ -165,7 +165,7 @@
   // Inform the syncer that its cached information about a type is obsolete.
   virtual void OnIncomingInvalidation(
       ModelType type,
-      std::unique_ptr<InvalidationInterface> invalidation) = 0;
+      std::unique_ptr<SyncInvalidation> invalidation) = 0;
 
   // Adds a listener to be notified of sync events.
   // NOTE: It is OK (in fact, it's probably a good idea) to call this before
diff --git a/components/sync/engine/sync_manager_impl.cc b/components/sync/engine/sync_manager_impl.cc
index cd27f1cc..aff19ea6c 100644
--- a/components/sync/engine/sync_manager_impl.cc
+++ b/components/sync/engine/sync_manager_impl.cc
@@ -15,8 +15,8 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
-#include "components/sync/base/invalidation_interface.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/base/sync_invalidation.h"
 #include "components/sync/engine/cancelation_signal.h"
 #include "components/sync/engine/configure_reason.h"
 #include "components/sync/engine/engine_components_factory.h"
@@ -428,7 +428,7 @@
 
 void SyncManagerImpl::OnIncomingInvalidation(
     ModelType type,
-    std::unique_ptr<InvalidationInterface> invalidation) {
+    std::unique_ptr<SyncInvalidation> invalidation) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   sync_status_tracker_->IncrementNotificationsReceived();
diff --git a/components/sync/engine/sync_manager_impl.h b/components/sync/engine/sync_manager_impl.h
index 4fbcf79..e720160 100644
--- a/components/sync/engine/sync_manager_impl.h
+++ b/components/sync/engine/sync_manager_impl.h
@@ -69,7 +69,7 @@
   void SetInvalidatorEnabled(bool invalidator_enabled) override;
   void OnIncomingInvalidation(
       ModelType type,
-      std::unique_ptr<InvalidationInterface> invalidation) override;
+      std::unique_ptr<SyncInvalidation> invalidation) override;
   void AddObserver(SyncManager::Observer* observer) override;
   void RemoveObserver(SyncManager::Observer* observer) override;
   void ShutdownOnSyncThread() override;
diff --git a/components/sync/engine/sync_scheduler.h b/components/sync/engine/sync_scheduler.h
index 48676936..bd8514a 100644
--- a/components/sync/engine/sync_scheduler.h
+++ b/components/sync/engine/sync_scheduler.h
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/time/time.h"
-#include "components/sync/base/invalidation_interface.h"
+#include "components/sync/base/sync_invalidation.h"
 #include "components/sync/engine/cycle/sync_cycle.h"
 #include "services/network/public/mojom/network_change_manager.mojom.h"
 
@@ -79,7 +79,7 @@
   // order to fetch the update.
   virtual void ScheduleInvalidationNudge(
       ModelType type,
-      std::unique_ptr<InvalidationInterface> invalidation) = 0;
+      std::unique_ptr<SyncInvalidation> invalidation) = 0;
 
   // Requests a non-blocking initial sync request for the specified type.
   //
diff --git a/components/sync/engine/sync_scheduler_impl.cc b/components/sync/engine/sync_scheduler_impl.cc
index 3684ce8..41a2125 100644
--- a/components/sync/engine/sync_scheduler_impl.cc
+++ b/components/sync/engine/sync_scheduler_impl.cc
@@ -328,7 +328,7 @@
 
 void SyncSchedulerImpl::ScheduleInvalidationNudge(
     ModelType model_type,
-    std::unique_ptr<InvalidationInterface> invalidation) {
+    std::unique_ptr<SyncInvalidation> invalidation) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!syncer_->IsSyncing());
 
diff --git a/components/sync/engine/sync_scheduler_impl.h b/components/sync/engine/sync_scheduler_impl.h
index 2b709d4f..88b1366 100644
--- a/components/sync/engine/sync_scheduler_impl.h
+++ b/components/sync/engine/sync_scheduler_impl.h
@@ -55,7 +55,7 @@
   void ScheduleLocalRefreshRequest(ModelTypeSet types) override;
   void ScheduleInvalidationNudge(
       ModelType type,
-      std::unique_ptr<InvalidationInterface> invalidation) override;
+      std::unique_ptr<SyncInvalidation> invalidation) override;
   void ScheduleInitialSyncNudge(ModelType model_type) override;
   void SetNotificationsEnabled(bool notifications_enabled) override;
 
diff --git a/components/sync/engine/sync_scheduler_impl_unittest.cc b/components/sync/engine/sync_scheduler_impl_unittest.cc
index 1365c443..a06b49c 100644
--- a/components/sync/engine/sync_scheduler_impl_unittest.cc
+++ b/components/sync/engine/sync_scheduler_impl_unittest.cc
@@ -391,7 +391,7 @@
     return scheduler_->retry_timer_.GetCurrentDelay();
   }
 
-  static std::unique_ptr<InvalidationInterface> BuildInvalidation(
+  static std::unique_ptr<SyncInvalidation> BuildInvalidation(
       int64_t version,
       const std::string& payload) {
     return MockInvalidation::Build(version, payload);
diff --git a/components/sync/test/engine/fake_sync_manager.cc b/components/sync/test/engine/fake_sync_manager.cc
index d767a817..c6abeae 100644
--- a/components/sync/test/engine/fake_sync_manager.cc
+++ b/components/sync/test/engine/fake_sync_manager.cc
@@ -172,7 +172,7 @@
 
 void FakeSyncManager::OnIncomingInvalidation(
     ModelType type,
-    std::unique_ptr<InvalidationInterface> invalidation) {
+    std::unique_ptr<SyncInvalidation> invalidation) {
   num_invalidations_received_[type]++;
 }
 
diff --git a/components/sync/test/engine/fake_sync_manager.h b/components/sync/test/engine/fake_sync_manager.h
index e331fb9..d16180c 100644
--- a/components/sync/test/engine/fake_sync_manager.h
+++ b/components/sync/test/engine/fake_sync_manager.h
@@ -82,7 +82,7 @@
                        base::OnceClosure ready_task) override;
   void OnIncomingInvalidation(
       ModelType type,
-      std::unique_ptr<InvalidationInterface> interface) override;
+      std::unique_ptr<SyncInvalidation> interface) override;
   void SetInvalidatorEnabled(bool invalidator_enabled) override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
diff --git a/components/sync/test/engine/fake_sync_scheduler.cc b/components/sync/test/engine/fake_sync_scheduler.cc
index a5aec03a..243ce25 100644
--- a/components/sync/test/engine/fake_sync_scheduler.cc
+++ b/components/sync/test/engine/fake_sync_scheduler.cc
@@ -22,7 +22,7 @@
 
 void FakeSyncScheduler::ScheduleInvalidationNudge(
     ModelType type,
-    std::unique_ptr<InvalidationInterface> interface) {}
+    std::unique_ptr<SyncInvalidation> interface) {}
 
 void FakeSyncScheduler::ScheduleConfiguration(
     sync_pb::SyncEnums::GetUpdatesOrigin origin,
diff --git a/components/sync/test/engine/fake_sync_scheduler.h b/components/sync/test/engine/fake_sync_scheduler.h
index d536d35f..bd22268b 100644
--- a/components/sync/test/engine/fake_sync_scheduler.h
+++ b/components/sync/test/engine/fake_sync_scheduler.h
@@ -26,7 +26,7 @@
   void ScheduleLocalRefreshRequest(ModelTypeSet types) override;
   void ScheduleInvalidationNudge(
       ModelType type,
-      std::unique_ptr<InvalidationInterface> interface) override;
+      std::unique_ptr<SyncInvalidation> interface) override;
   void ScheduleConfiguration(sync_pb::SyncEnums::GetUpdatesOrigin origin,
                              ModelTypeSet types_to_download,
                              base::OnceClosure ready_task) override;
diff --git a/components/sync/test/mock_invalidation.h b/components/sync/test/mock_invalidation.h
index 9db15af..40b664e 100644
--- a/components/sync/test/mock_invalidation.h
+++ b/components/sync/test/mock_invalidation.h
@@ -10,13 +10,13 @@
 #include <memory>
 #include <string>
 
-#include "components/sync/base/invalidation_interface.h"
+#include "components/sync/base/sync_invalidation.h"
 
 namespace syncer {
 
-// An InvalidationInterface used by sync for testing.
+// A SyncInvalidation used by sync for testing.
 // It does not support any form of acknowledgements.
-class MockInvalidation : public InvalidationInterface {
+class MockInvalidation : public SyncInvalidation {
  public:
   // Helpers to build new MockInvalidations.
   static std::unique_ptr<MockInvalidation> BuildUnknownVersion();
@@ -25,7 +25,7 @@
 
   ~MockInvalidation() override;
 
-  // Implementation of InvalidationInterface.
+  // Implementation of SyncInvalidation.
   bool IsUnknownVersion() const override;
   const std::string& GetPayload() const override;
   int64_t GetVersion() const override;
diff --git a/components/test/data/payments/has_enrolled_instrument.js b/components/test/data/payments/has_enrolled_instrument.js
index 54f3bf51..5189fa4 100644
--- a/components/test/data/payments/has_enrolled_instrument.js
+++ b/components/test/data/payments/has_enrolled_instrument.js
@@ -5,27 +5,34 @@
  */
 
 /**
- * Builds a PaymentRequest for 'basic-card' with the given options.
+ * Builds a PaymentRequest for the given method with the given options.
  * @param {PaymentOptions} options - The payment options to use.
+ * @param {DOMString} method - The payment method to use. Optional. If not
+ * specified, then 'basic-card' is used.
  * @return {PaymentRequest} The new PaymentRequest object.
  */
-function buildPaymentRequest(options) {
+function buildPaymentRequest(options, method) {
+  if (!method) {
+    method = 'basic-card';
+  }
   return new PaymentRequest(
-      [{supportedMethods: 'basic-card'}],
+      [{supportedMethods: method}],
       {total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}}},
       options);
 }
 
 /**
- * Checks the hasEnrolledInstrument() value for 'basic-card' with the given
- * options.
+ * Checks the hasEnrolledInstrument() value for the given payment method with
+ * the given options.
  * @param {PaymentOptions} options - The payment options to use.
+ * @param {DOMString} method - The payment method to use. Optional. If not
+ * specified, then 'basic-card' is used.
  * @return {Promise<boolean|string>} The boolean value of
  * hasEnrolledInstrument() or the error message string.
  */
-async function hasEnrolledInstrument(options) { // eslint-disable-line no-unused-vars,max-len
+async function hasEnrolledInstrument(options, method) { // eslint-disable-line no-unused-vars,max-len
   try {
-    return await buildPaymentRequest(options).hasEnrolledInstrument();
+    return await buildPaymentRequest(options, method).hasEnrolledInstrument();
   } catch (e) {
     return e.toString();
   }
diff --git a/components/translate/core/browser/translate_manager_unittest.cc b/components/translate/core/browser/translate_manager_unittest.cc
index fea1ccb..b285f28 100644
--- a/components/translate/core/browser/translate_manager_unittest.cc
+++ b/components/translate/core/browser/translate_manager_unittest.cc
@@ -684,15 +684,15 @@
 
   base::HistogramTester histogram_tester;
   prefs_.SetBoolean(prefs::kOfferTranslateEnabled, true);
-  translate_manager_->GetLanguageState()->LanguageDetermined("en", true);
+  translate_manager_->GetLanguageState()->LanguageDetermined("zu", true);
   network_notifier_.SimulateOnline();
 
-  translate_manager_->InitiateTranslation("en");
+  translate_manager_->InitiateTranslation("zu");
   EXPECT_THAT(histogram_tester.GetAllSamples(kInitiationStatusName),
               ElementsAre(Bucket(metrics::INITIATION_STATUS_SHOW_INFOBAR, 1),
                           Bucket(metrics::INITIATION_STATUS_SHOW_ICON, 1)));
 
-  translate_manager_->TranslatePage("en", "hi", false);
+  translate_manager_->TranslatePage("zu", "hi", false);
 
   // Accept languages should now contain "hi" because the user chose to
   // translate to it once.
@@ -1137,7 +1137,7 @@
 TEST_F(TranslateManagerTest, PredefinedTargetLanguage) {
   PrepareTranslateManager();
   manager_->set_application_locale("en");
-  ASSERT_TRUE(TranslateDownloadManager::IsSupportedLanguage("en"));
+  ASSERT_TRUE(TranslateDownloadManager::IsSupportedLanguage("zu"));
 
   ON_CALL(mock_translate_client_, IsTranslatableURL(GURL::EmptyGURL()))
       .WillByDefault(Return(true));
@@ -1152,19 +1152,19 @@
       "ru",
       translate_manager_->GetLanguageState()->GetPredefinedTargetLanguage());
 
-  translate_manager_->GetLanguageState()->LanguageDetermined("en", true);
+  translate_manager_->GetLanguageState()->LanguageDetermined("zu", true);
 
   EXPECT_CALL(
       mock_translate_client_,
-      ShowTranslateUI(translate::TRANSLATE_STEP_BEFORE_TRANSLATE, "en", "ru",
+      ShowTranslateUI(translate::TRANSLATE_STEP_BEFORE_TRANSLATE, "zu", "ru",
                       TranslateErrors::NONE, /*triggered_from_menu=*/false))
       .WillOnce(Return(true));
 
   base::HistogramTester histogram_tester;
-  translate_manager_->InitiateTranslation("en");
+  translate_manager_->InitiateTranslation("zu");
   EXPECT_THAT(
       histogram_tester.GetAllSamples(kInitiationStatusName),
-      ElementsAre(Bucket(
+      ::testing::Contains(Bucket(
           metrics::INITIATION_STATUS_SHOW_UI_PREDEFINED_TARGET_LANGUAGE, 1)));
 }
 
diff --git a/components/translate/core/browser/translate_prefs_unittest.cc b/components/translate/core/browser/translate_prefs_unittest.cc
index eed9b5f..165d487d 100644
--- a/components/translate/core/browser/translate_prefs_unittest.cc
+++ b/components/translate/core/browser/translate_prefs_unittest.cc
@@ -1120,7 +1120,13 @@
   EXPECT_THAT(translate_prefs_->GetAlwaysTranslateLanguages(), IsEmpty());
 }
 
-TEST_F(TranslatePrefsTest, CanTranslateLanguage) {
+// Failing on Android - crbug.com/1286360
+#if BUILDFLAG(IS_ANDROID)
+#define MAYBE_CanTranslateLanguage DISABLED_CanTranslateLanguage
+#else
+#define MAYBE_CanTranslateLanguage CanTranslateLanguage
+#endif
+TEST_F(TranslatePrefsTest, MAYBE_CanTranslateLanguage) {
   prefs_.SetString(language::prefs::kAcceptLanguages, "en");
   TranslateDownloadManager::GetInstance()->set_application_locale("en");
 
@@ -1138,10 +1144,12 @@
   EXPECT_FALSE(translate_prefs_->CanTranslateLanguage(
       &translate_accept_languages, "en"));
 
-  // Blocked languages that are not in accept languages are not blocked.
-  translate_prefs_->BlockLanguage("de");
-  EXPECT_TRUE(translate_prefs_->CanTranslateLanguage(
-      &translate_accept_languages, "de"));
+  if (!TranslatePrefs::IsDetailedLanguageSettingsEnabled()) {
+    // Blocked languages that are not in accept languages are not blocked.
+    translate_prefs_->BlockLanguage("de");
+    EXPECT_TRUE(translate_prefs_->CanTranslateLanguage(
+        &translate_accept_languages, "de"));
+  }
 
 // When the detailed language settings are enabled blocked languages not in
 // accept languages can be translated.
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index fae4aae8..c92e6d2 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -158,6 +158,9 @@
     "frame_sinks/frame_sink_manager_impl.cc",
     "frame_sinks/frame_sink_manager_impl.h",
     "frame_sinks/frame_sink_observer.h",
+    "frame_sinks/gmb_video_frame_pool_context_provider.h",
+    "frame_sinks/gmb_video_frame_pool_context_provider_impl.cc",
+    "frame_sinks/gmb_video_frame_pool_context_provider_impl.h",
     "frame_sinks/gpu_vsync_begin_frame_source.cc",
     "frame_sinks/gpu_vsync_begin_frame_source.h",
     "frame_sinks/root_compositor_frame_sink_impl.cc",
@@ -169,6 +172,8 @@
     "frame_sinks/video_capture/frame_sink_video_capturer_impl.cc",
     "frame_sinks/video_capture/frame_sink_video_capturer_impl.h",
     "frame_sinks/video_capture/frame_sink_video_capturer_manager.h",
+    "frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc",
+    "frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h",
     "frame_sinks/video_capture/in_flight_frame_delivery.cc",
     "frame_sinks/video_capture/in_flight_frame_delivery.h",
     "frame_sinks/video_capture/shared_memory_video_frame_pool.cc",
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index e768356..1690655 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -3702,10 +3702,8 @@
     // the content might be mastered in 0-1000 nits but the display only be able
     // to represent 0 to 500.
     adjusted_src_color_space = src_color_space.GetWithSDRWhiteLevel(
-        current_frame()->display_color_spaces.GetSDRWhiteLevel());
+        current_frame()->display_color_spaces.GetSDRMaxLuminanceNits());
   }
-  // TODO(b/183236148): consider using the destination's HDR static metadata
-  // in current_frame()->display_color_spaces.hdr_static_metadata().
 
   ProgramKey program_key = program_key_no_color;
   const gfx::ColorTransform* color_transform =
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 5ee23580..9f6d62b 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -224,7 +224,7 @@
           auto adjusted_color_space = src_color_space;
           if (src_color_space.IsHDR()) {
             adjusted_color_space = src_color_space.GetWithSDRWhiteLevel(
-                drawing_frame.display_color_spaces.GetSDRWhiteLevel());
+                drawing_frame.display_color_spaces.GetSDRMaxLuminanceNits());
           }
           SCOPED_TRACE(
               base::StringPrintf("adjusted_color_space=%s, dst_color_space=%s",
@@ -287,7 +287,7 @@
   void TestShadersWithSDRWhiteLevel(const ProgramKey& program_key,
                                     float sdr_white_level) {
     GLRenderer::DrawingFrame frame;
-    frame.display_color_spaces.SetSDRWhiteLevel(sdr_white_level);
+    frame.display_color_spaces.SetSDRMaxLuminanceNits(sdr_white_level);
     TestShaderWithDrawingFrame(program_key, frame, false);
   }
 
@@ -998,7 +998,7 @@
 
     constexpr float kSDRWhiteLevel = 123.0f;
     gfx::DisplayColorSpaces display_color_spaces;
-    display_color_spaces.SetSDRWhiteLevel(kSDRWhiteLevel);
+    display_color_spaces.SetSDRMaxLuminanceNits(kSDRWhiteLevel);
 
     DrawFrame(renderer_.get(), viewport_size, display_color_spaces);
 
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index bf5dddcf..1bc1f65 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -2461,7 +2461,7 @@
   // If the input color space is HDR, and it did not specify a white level,
   // override it with the frame's white level.
   gfx::ColorSpace adjusted_src = src.GetWithSDRWhiteLevel(
-      current_frame()->display_color_spaces.GetSDRWhiteLevel());
+      current_frame()->display_color_spaces.GetSDRMaxLuminanceNits());
 
   sk_sp<SkRuntimeEffect>& effect = color_filter_cache_[dst][adjusted_src];
   if (!effect) {
diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.cc b/components/viz/service/display_embedder/output_surface_provider_impl.cc
index e0afde4b0..7beb395 100644
--- a/components/viz/service/display_embedder/output_surface_provider_impl.cc
+++ b/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -75,13 +75,13 @@
     GpuServiceImpl* gpu_service_impl,
     gpu::CommandBufferTaskExecutor* task_executor,
     gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
-    std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
+    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     gpu::ImageFactory* image_factory,
     bool headless)
     : gpu_service_impl_(gpu_service_impl),
       task_executor_(task_executor),
       gpu_channel_manager_delegate_(gpu_channel_manager_delegate),
-      gpu_memory_buffer_manager_(std::move(gpu_memory_buffer_manager)),
+      gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
       image_factory_(image_factory),
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
       headless_(headless) {}
diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.h b/components/viz/service/display_embedder/output_surface_provider_impl.h
index 07f266d..548de8f 100644
--- a/components/viz/service/display_embedder/output_surface_provider_impl.h
+++ b/components/viz/service/display_embedder/output_surface_provider_impl.h
@@ -42,7 +42,7 @@
       GpuServiceImpl* gpu_service_impl,
       gpu::CommandBufferTaskExecutor* task_executor,
       gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
-      std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
+      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       gpu::ImageFactory* image_factory,
       bool headless);
   // Software compositing only.
@@ -76,7 +76,7 @@
   const raw_ptr<GpuServiceImpl> gpu_service_impl_;
   const raw_ptr<gpu::CommandBufferTaskExecutor> task_executor_;
   const raw_ptr<gpu::GpuChannelManagerDelegate> gpu_channel_manager_delegate_;
-  std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
+  const raw_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
   const raw_ptr<gpu::ImageFactory> image_factory_;
 
 #if defined(OS_WIN)
diff --git a/components/viz/service/frame_sinks/DEPS b/components/viz/service/frame_sinks/DEPS
index 5174f6a..87132f8e 100644
--- a/components/viz/service/frame_sinks/DEPS
+++ b/components/viz/service/frame_sinks/DEPS
@@ -9,8 +9,12 @@
   "+components/viz/service/performance_hint",
   "+components/viz/service/surfaces",
   "+components/viz/service/transitions",
+  "+gpu/command_buffer/service/shared_context_state.h",
   "+gpu/ipc/common",
+  "+gpu/ipc/scheduler_sequence.h",
+  "+gpu/ipc/shared_image_interface_in_process.h",
   "+mojo/public",
+  "+media/video",
 ]
 
 specific_include_rules = {
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 0e5b34a..af66991 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -31,9 +31,11 @@
 FrameSinkManagerImpl::InitParams::InitParams() = default;
 FrameSinkManagerImpl::InitParams::InitParams(
     SharedBitmapManager* shared_bitmap_manager,
-    OutputSurfaceProvider* output_surface_provider)
+    OutputSurfaceProvider* output_surface_provider,
+    GmbVideoFramePoolContextProvider* gmb_context_provider)
     : shared_bitmap_manager(shared_bitmap_manager),
-      output_surface_provider(output_surface_provider) {}
+      output_surface_provider(output_surface_provider),
+      gmb_context_provider(gmb_context_provider) {}
 FrameSinkManagerImpl::InitParams::InitParams(InitParams&& other) = default;
 FrameSinkManagerImpl::InitParams::~InitParams() = default;
 FrameSinkManagerImpl::InitParams& FrameSinkManagerImpl::InitParams::operator=(
@@ -64,6 +66,7 @@
 FrameSinkManagerImpl::FrameSinkManagerImpl(const InitParams& params)
     : shared_bitmap_manager_(params.shared_bitmap_manager),
       output_surface_provider_(params.output_surface_provider),
+      gmb_context_provider_(params.gmb_context_provider),
       surface_manager_(this, params.activation_deadline_in_frames),
       hit_test_manager_(surface_manager()),
       restart_id_(params.restart_id),
@@ -314,7 +317,7 @@
 void FrameSinkManagerImpl::CreateVideoCapturer(
     mojo::PendingReceiver<mojom::FrameSinkVideoCapturer> receiver) {
   video_capturers_.emplace(std::make_unique<FrameSinkVideoCapturerImpl>(
-      this, std::move(receiver),
+      this, gmb_context_provider_, std::move(receiver),
       std::make_unique<media::VideoCaptureOracle>(
           true /* enable_auto_throttling */),
       log_capture_pipeline_in_webrtc_));
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index d912483..502d236 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -53,6 +53,7 @@
 class HintSessionFactory;
 class OutputSurfaceProvider;
 class SharedBitmapManager;
+class GmbVideoFramePoolContextProvider;
 
 // FrameSinkManagerImpl manages BeginFrame hierarchy. This is the implementation
 // detail for FrameSinkManagerImpl.
@@ -67,7 +68,8 @@
     InitParams();
     explicit InitParams(
         SharedBitmapManager* shared_bitmap_manager,
-        OutputSurfaceProvider* output_surface_provider = nullptr);
+        OutputSurfaceProvider* output_surface_provider = nullptr,
+        GmbVideoFramePoolContextProvider* gmb_context_provider = nullptr);
     InitParams(InitParams&& other);
     ~InitParams();
     InitParams& operator=(InitParams&& other);
@@ -76,6 +78,7 @@
     absl::optional<uint32_t> activation_deadline_in_frames =
         kDefaultActivationDeadlineInFrames;
     raw_ptr<OutputSurfaceProvider> output_surface_provider = nullptr;
+    raw_ptr<GmbVideoFramePoolContextProvider> gmb_context_provider = nullptr;
     uint32_t restart_id = BeginFrameSource::kNotRestartableId;
     bool run_all_compositor_stages_before_draw = false;
     bool log_capture_pipeline_in_webrtc = false;
@@ -327,6 +330,8 @@
   // Provides an output surface for CreateRootCompositorFrameSink().
   const raw_ptr<OutputSurfaceProvider> output_surface_provider_;
 
+  const raw_ptr<GmbVideoFramePoolContextProvider> gmb_context_provider_;
+
   SurfaceManager surface_manager_;
 
   // Must be created after and destroyed before |surface_manager_|.
diff --git a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h
new file mode 100644
index 0000000..6b3f7587bf
--- /dev/null
+++ b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
+
+namespace viz {
+
+// Context provider for contexts needed to create instances of
+// `media::RenderableGpuMemoryBufferVideoFramePool`. Used to create an instance
+// of `FrameSinkManagerImpl` capable of creating `FrameSinkVideoCapturerImpl`
+// with `GpuMemoryBuffer` support.
+class GmbVideoFramePoolContextProvider {
+ public:
+  virtual ~GmbVideoFramePoolContextProvider() = default;
+
+  // Creates new context that can then subsequently be used to create
+  // a media::RenderableGpuMemoryBufferVideoFramePool. The |on_context_lost|
+  // will be invoked to notify the callers that the context returned from the
+  // call is no longer functional. It will be called on the current sequence.
+  virtual std::unique_ptr<
+      media::RenderableGpuMemoryBufferVideoFramePool::Context>
+  CreateContext(base::OnceClosure on_context_lost) = 0;
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_H_
diff --git a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc
new file mode 100644
index 0000000..162e4f7d
--- /dev/null
+++ b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc
@@ -0,0 +1,177 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/task/bind_post_task.h"
+#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
+#include "components/viz/service/gl/gpu_service_impl.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/ipc/scheduler_sequence.h"
+#include "gpu/ipc/shared_image_interface_in_process.h"
+
+namespace viz {
+
+class GmbVideoFramePoolContext
+    : public media::RenderableGpuMemoryBufferVideoFramePool::Context,
+      public gpu::SharedContextState::ContextLostObserver {
+ public:
+  explicit GmbVideoFramePoolContext(
+      GpuServiceImpl* gpu_service,
+      InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager,
+      base::OnceClosure on_context_lost)
+      : gpu_service_(gpu_service),
+        gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+        on_context_lost_(
+            base::BindPostTask(base::SequencedTaskRunnerHandle::Get(),
+                               std::move(on_context_lost))) {
+    DETACH_FROM_SEQUENCE(gpu_sequence_checker_);
+
+    sequence_ = std::make_unique<gpu::SchedulerSequence>(
+        gpu_service_->GetGpuScheduler(), gpu_service_->main_runner());
+
+    base::WaitableEvent event;
+
+    sequence_->ScheduleTask(
+        base::BindOnce(&GmbVideoFramePoolContext::InitializeOnGpu,
+                       base::Unretained(this), &event),
+        {});
+
+    event.Wait();
+  }
+
+  ~GmbVideoFramePoolContext() override {
+    // SharedImageInterfaceInProcess' dtor blocks on GPU, which we want to do as
+    // well, so run it now before we grab the GPU thread:
+    sii_in_process_ = nullptr;
+
+    base::WaitableEvent event;
+
+    sequence_->ScheduleTask(
+        base::BindOnce(&GmbVideoFramePoolContext::DestroyOnGpu,
+                       base::Unretained(this), &event),
+        {});
+
+    event.Wait();
+
+    sequence_ = nullptr;
+  }
+
+  // Allocate a GpuMemoryBuffer.
+  std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
+      const gfx::Size& size,
+      gfx::BufferFormat format,
+      gfx::BufferUsage usage) override {
+    return gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
+        size, format, usage, gpu::kNullSurfaceHandle, nullptr);
+  }
+
+  // Create a SharedImage representation of a plane of a GpuMemoryBuffer
+  // allocated by this interface. Populate `mailbox` and `sync_token`.
+  void CreateSharedImage(gfx::GpuMemoryBuffer* gpu_memory_buffer,
+                         gfx::BufferPlane plane,
+                         const gfx::ColorSpace& color_space,
+                         GrSurfaceOrigin surface_origin,
+                         SkAlphaType alpha_type,
+                         uint32_t usage,
+                         gpu::Mailbox& mailbox,
+                         gpu::SyncToken& sync_token) override {
+    mailbox = sii_in_process_->CreateSharedImage(
+        gpu_memory_buffer, gpu_memory_buffer_manager_, plane, color_space,
+        surface_origin, alpha_type, usage);
+
+    sync_token = sii_in_process_->GenVerifiedSyncToken();
+  }
+
+  // Destroy a SharedImage created by this interface.
+  void DestroySharedImage(const gpu::SyncToken& sync_token,
+                          const gpu::Mailbox& mailbox) override {
+    sii_in_process_->DestroySharedImage(sync_token, mailbox);
+  }
+
+ private:
+  void InitializeOnGpu(base::WaitableEvent* event) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+    DCHECK(!initialized_);
+    DCHECK(gpu_service_);
+
+    shared_context_state_ = gpu_service_->GetContextState();
+    DCHECK(shared_context_state_);
+
+    shared_context_state_->AddContextLostObserver(this);
+
+    // TODO(bialpio): Move construction to the viz thread once it is no longer
+    // necessary to dereference `shared_context_state_` to grab the memory
+    // tracker from it.
+    sii_in_process_ = std::make_unique<gpu::SharedImageInterfaceInProcess>(
+        sequence_.get(), gpu_service_->sync_point_manager(),
+        gpu_service_->gpu_preferences(),
+        gpu_service_->gpu_driver_bug_workarounds(),
+        gpu_service_->gpu_feature_info(), shared_context_state_.get(),
+        gpu_service_->mailbox_manager(), gpu_service_->shared_image_manager(),
+        gpu_service_->gpu_image_factory(),
+        shared_context_state_->memory_tracker());
+    DCHECK(sii_in_process_);
+
+    initialized_ = true;
+
+    event->Signal();
+  }
+
+  void DestroyOnGpu(base::WaitableEvent* event) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+    DCHECK(initialized_);
+
+    shared_context_state_->RemoveContextLostObserver(this);
+    shared_context_state_ = nullptr;
+
+    event->Signal();
+  }
+
+  // gpu::SharedContextState::ContextLostObserver implementation:
+  void OnContextLost() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+
+    DCHECK(on_context_lost_);
+    std::move(on_context_lost_).Run();
+  }
+
+  const raw_ptr<GpuServiceImpl> gpu_service_;
+  const raw_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+
+  // Closure that we need to call when context loss happens.
+  base::OnceClosure on_context_lost_;
+
+  // True iff the context was initialized on GPU.
+  bool initialized_ = false;
+
+  std::unique_ptr<gpu::SchedulerSequence> sequence_;
+  scoped_refptr<gpu::SharedContextState> shared_context_state_;
+
+  std::unique_ptr<gpu::SharedImageInterfaceInProcess> sii_in_process_;
+
+  SEQUENCE_CHECKER(gpu_sequence_checker_);
+};
+
+GmbVideoFramePoolContextProviderImpl::GmbVideoFramePoolContextProviderImpl(
+    GpuServiceImpl* gpu_service,
+    InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager)
+    : gpu_service_(gpu_service),
+      gpu_memory_buffer_manager_(gpu_memory_buffer_manager) {}
+
+GmbVideoFramePoolContextProviderImpl::~GmbVideoFramePoolContextProviderImpl() =
+    default;
+
+std::unique_ptr<media::RenderableGpuMemoryBufferVideoFramePool::Context>
+GmbVideoFramePoolContextProviderImpl::CreateContext(
+    base::OnceClosure on_context_lost) {
+  return std::make_unique<GmbVideoFramePoolContext>(
+      gpu_service_, gpu_memory_buffer_manager_, std::move(on_context_lost));
+}
+
+}  // namespace viz
diff --git a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h
new file mode 100644
index 0000000..8cd3cf4
--- /dev/null
+++ b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h
@@ -0,0 +1,43 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_IMPL_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_IMPL_H_
+
+#include <memory>
+
+#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h"
+#include "components/viz/service/viz_service_export.h"
+#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
+
+namespace viz {
+
+class GpuServiceImpl;
+class InProcessGpuMemoryBufferManager;
+
+class VIZ_SERVICE_EXPORT GmbVideoFramePoolContextProviderImpl
+    : public GmbVideoFramePoolContextProvider {
+ public:
+  explicit GmbVideoFramePoolContextProviderImpl(
+      GpuServiceImpl* gpu_service,
+      InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager);
+
+  GmbVideoFramePoolContextProviderImpl(
+      const GmbVideoFramePoolContextProviderImpl& other) = delete;
+  GmbVideoFramePoolContextProviderImpl& operator=(
+      const GmbVideoFramePoolContextProviderImpl& other) = delete;
+
+  ~GmbVideoFramePoolContextProviderImpl() override;
+
+  std::unique_ptr<media::RenderableGpuMemoryBufferVideoFramePool::Context>
+  CreateContext(base::OnceClosure on_context_lost) override;
+
+ private:
+  const raw_ptr<GpuServiceImpl> gpu_service_;
+  const raw_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_IMPL_H_
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 1ffccdf..2fdd804 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -71,6 +71,7 @@
 
 FrameSinkVideoCapturerImpl::FrameSinkVideoCapturerImpl(
     FrameSinkVideoCapturerManager* frame_sink_manager,
+    GmbVideoFramePoolContextProvider* gmb_video_frame_pool_context_provider,
     mojo::PendingReceiver<mojom::FrameSinkVideoCapturer> receiver,
     std::unique_ptr<media::VideoCaptureOracle> oracle,
     bool log_to_webrtc)
@@ -78,6 +79,8 @@
       copy_request_source_(base::UnguessableToken::Create()),
       clock_(base::DefaultTickClock::GetInstance()),
       oracle_(std::move(oracle)),
+      gmb_video_frame_pool_context_provider_(
+          gmb_video_frame_pool_context_provider),
       frame_pool_(
           std::make_unique<SharedMemoryVideoFramePool>(kFramePoolCapacity)),
       feedback_weak_factory_(oracle_.get()),
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
index 1084a75..4f5aa36 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
@@ -27,8 +27,10 @@
 #include "components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h"
 #include "components/viz/service/frame_sinks/video_capture/video_capture_overlay.h"
 #include "components/viz/service/frame_sinks/video_capture/video_frame_pool.h"
+#include "components/viz/service/viz_service_export.h"
 #include "media/base/video_frame.h"
 #include "media/capture/content/video_capture_oracle.h"
+#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -46,6 +48,7 @@
 
 class CopyOutputResult;
 class FrameSinkVideoCapturerManager;
+class GmbVideoFramePoolContextProvider;
 
 // Captures the frames of a CompositorFrameSink's surface as a video stream. See
 // mojom for usage details.
@@ -74,11 +77,14 @@
       public VideoCaptureOverlay::FrameSource,
       public mojom::FrameSinkVideoCapturer {
  public:
+  using GpuMemoryBufferVideoFramePoolContext =
+      media::RenderableGpuMemoryBufferVideoFramePool::Context;
   // |frame_sink_manager| must outlive this instance. Binds this instance to the
   // Mojo message pipe endpoint in |receiver|, but |receiver| may be empty for
   // unit testing.
   FrameSinkVideoCapturerImpl(
       FrameSinkVideoCapturerManager* frame_sink_manager,
+      GmbVideoFramePoolContextProvider* gmb_video_frame_pool_context_provider,
       mojo::PendingReceiver<mojom::FrameSinkVideoCapturer> receiver,
       std::unique_ptr<media::VideoCaptureOracle> oracle,
       bool log_to_webrtc);
@@ -378,6 +384,9 @@
   // Note: This is always set, but the instance is overridden for unit testing.
   absl::optional<base::OneShotTimer> refresh_frame_retry_timer_;
 
+  raw_ptr<GmbVideoFramePoolContextProvider>
+      gmb_video_frame_pool_context_provider_;
+
   // Provides a pool of VideoFrames that can be efficiently delivered across
   // processes. The size of this pool is used to limit the maximum number of
   // frames in-flight at any one time.
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
index 3f66223..9c085a4 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
@@ -464,7 +464,8 @@
         true /* enable_auto_throttling */);
     oracle_ = oracle.get();
     capturer_ = std::make_unique<FrameSinkVideoCapturerImpl>(
-        &frame_sink_manager_, mojo::NullReceiver(), std::move(oracle), false);
+        &frame_sink_manager_, nullptr, mojo::NullReceiver(), std::move(oracle),
+        false);
   }
 
   void SetUp() override {
diff --git a/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc b/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc
new file mode 100644
index 0000000..77994d4
--- /dev/null
+++ b/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc
@@ -0,0 +1,88 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h"
+
+#include <utility>
+
+#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h"
+
+namespace viz {
+
+GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool(
+    int capacity,
+    GmbVideoFramePoolContextProvider* context_provider)
+    : VideoFramePool(capacity), context_provider_(context_provider) {
+  RecreateVideoFramePool();
+}
+
+GpuMemoryBufferVideoFramePool::~GpuMemoryBufferVideoFramePool() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+scoped_refptr<media::VideoFrame>
+GpuMemoryBufferVideoFramePool::ReserveVideoFrame(media::VideoPixelFormat format,
+                                                 const gfx::Size& size) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_EQ(format, media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+  DCHECK_LE(num_reserved_frames_, capacity());
+
+  if (num_reserved_frames_ == capacity()) {
+    return nullptr;
+  }
+
+  scoped_refptr<media::VideoFrame> result =
+      video_frame_pool_->MaybeCreateVideoFrame(size,
+                                               gfx::ColorSpace::CreateREC709());
+
+  if (result) {
+    num_reserved_frames_++;
+    result->AddDestructionObserver(base::BindOnce(
+        &GpuMemoryBufferVideoFramePool::OnVideoFrameDestroyed,
+        weak_factory_.GetWeakPtr(), video_frame_pool_generation_));
+  }
+
+  return result;
+}
+
+media::mojom::VideoBufferHandlePtr
+GpuMemoryBufferVideoFramePool::CloneHandleForDelivery(
+    const media::VideoFrame& frame) {
+  DCHECK(frame.HasGpuMemoryBuffer());
+
+  return media::mojom::VideoBufferHandle::NewGpuMemoryBufferHandle(
+      frame.GetGpuMemoryBuffer()->CloneHandle());
+}
+
+size_t GpuMemoryBufferVideoFramePool::GetNumberOfReservedFrames() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  return num_reserved_frames_;
+}
+
+void GpuMemoryBufferVideoFramePool::RecreateVideoFramePool() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  auto pool_context = context_provider_->CreateContext(
+      base::BindOnce(&GpuMemoryBufferVideoFramePool::RecreateVideoFramePool,
+                     weak_factory_.GetWeakPtr()));
+  video_frame_pool_ = media::RenderableGpuMemoryBufferVideoFramePool::Create(
+      std::move(pool_context));
+
+  video_frame_pool_generation_++;
+  num_reserved_frames_ = 0;
+}
+
+void GpuMemoryBufferVideoFramePool::OnVideoFrameDestroyed(
+    uint32_t frame_pool_generation) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (frame_pool_generation == video_frame_pool_generation_) {
+    DCHECK_GT(num_reserved_frames_, 0u);
+
+    num_reserved_frames_--;
+  }
+}
+
+}  // namespace viz
diff --git a/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h b/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h
new file mode 100644
index 0000000..97019e0be
--- /dev/null
+++ b/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h
@@ -0,0 +1,75 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_VIDEO_FRAME_POOL_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_VIDEO_FRAME_POOL_H_
+
+#include <memory>
+
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/frame_sinks/video_capture/video_frame_pool.h"
+#include "components/viz/service/viz_service_export.h"
+#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
+
+namespace viz {
+
+class GmbVideoFramePoolContextProvider;
+
+class VIZ_SERVICE_EXPORT GpuMemoryBufferVideoFramePool : public VideoFramePool {
+ public:
+  // Creates new pool instance with specified |capacity|.
+  // The |context_provider| must outlive this instance.
+  explicit GpuMemoryBufferVideoFramePool(
+      int capacity,
+      GmbVideoFramePoolContextProvider* context_provider);
+  ~GpuMemoryBufferVideoFramePool() override;
+
+  GpuMemoryBufferVideoFramePool(const GpuMemoryBufferVideoFramePool&& other) =
+      delete;
+  GpuMemoryBufferVideoFramePool& operator=(
+      const GpuMemoryBufferVideoFramePool& other) = delete;
+
+  // VideoFramePool implementation:
+  scoped_refptr<media::VideoFrame> ReserveVideoFrame(
+      media::VideoPixelFormat format,
+      const gfx::Size& size) override;
+
+  media::mojom::VideoBufferHandlePtr CloneHandleForDelivery(
+      const media::VideoFrame& frame) override;
+
+  size_t GetNumberOfReservedFrames() const override;
+
+ private:
+  void RecreateVideoFramePool();
+
+  // Notify the pool that a video frame from |frame_pool_generation| was
+  // destroyed. If the generation matches the current pool generation, the
+  // number of reserved frames will be decremented.
+  void OnVideoFrameDestroyed(uint32_t frame_pool_generation);
+
+  raw_ptr<GmbVideoFramePoolContextProvider> context_provider_
+      GUARDED_BY_CONTEXT(sequence_checker_);
+
+  std::unique_ptr<media::RenderableGpuMemoryBufferVideoFramePool>
+      video_frame_pool_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+  // Number of reserved video frames.
+  size_t num_reserved_frames_ GUARDED_BY_CONTEXT(sequence_checker_) = 0;
+
+  // Current generation of |video_frame_pool_|. It will be bumped every time
+  // we detect a context lost event and recerate |video_frame_pool_| - this is
+  // needed so that we can correctly book-keep the number of reserved frames
+  // (when a video frame from previous generation is released, we don't want
+  // to decrement |num_reserved_frames_|).
+  uint32_t video_frame_pool_generation_ GUARDED_BY_CONTEXT(sequence_checker_) =
+      0;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<GpuMemoryBufferVideoFramePool> weak_factory_{this};
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_VIDEO_FRAME_POOL_H_
diff --git a/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc b/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc
index 5b63bcb..df89363 100644
--- a/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc
+++ b/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/viz/service/frame_sinks/video_capture/video_frame_pool.h"
+
 #include <algorithm>
 #include <memory>
 
-#include "components/viz/service/frame_sinks/video_capture/shared_memory_video_frame_pool.h"
-#include "components/viz/service/frame_sinks/video_capture/video_frame_pool.h"
-
 namespace viz {
 
 VideoFramePool::VideoFramePool(int capacity)
diff --git a/components/viz/service/main/viz_compositor_thread_runner_impl.cc b/components/viz/service/main/viz_compositor_thread_runner_impl.cc
index f579aaf3..54797f9 100644
--- a/components/viz/service/main/viz_compositor_thread_runner_impl.cc
+++ b/components/viz/service/main/viz_compositor_thread_runner_impl.cc
@@ -21,6 +21,7 @@
 #include "components/viz/service/display_embedder/output_surface_provider_impl.h"
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h"
 #include "components/viz/service/gl/gpu_service_impl.h"
 #include "gpu/config/gpu_finch_features.h"
 #include "gpu/config/gpu_switches.h"
@@ -160,14 +161,20 @@
   if (task_executor) {
     DCHECK(gpu_service);
     // Create OutputSurfaceProvider usable for GPU + software compositing.
-    auto gpu_memory_buffer_manager =
+    gpu_memory_buffer_manager_ =
         std::make_unique<InProcessGpuMemoryBufferManager>(
             gpu_service->gpu_memory_buffer_factory(),
             gpu_service->sync_point_manager());
     auto* image_factory = gpu_service->gpu_image_factory();
     output_surface_provider_ = std::make_unique<OutputSurfaceProviderImpl>(
         gpu_service, task_executor, gpu_service,
-        std::move(gpu_memory_buffer_manager), image_factory, headless);
+        gpu_memory_buffer_manager_.get(), image_factory, headless);
+
+    // Create video frame pool context provider that will enable the frame sink
+    // manager to create GMB-backed video frames.
+    gmb_video_frame_pool_context_provider_ =
+        std::make_unique<GmbVideoFramePoolContextProviderImpl>(
+            gpu_service, gpu_memory_buffer_manager_.get());
   } else {
     // Create OutputSurfaceProvider usable for software compositing only.
     output_surface_provider_ =
@@ -184,6 +191,8 @@
         params->activation_deadline_in_frames;
   }
   init_params.output_surface_provider = output_surface_provider_.get();
+  init_params.gmb_context_provider =
+      gmb_video_frame_pool_context_provider_.get();
   init_params.restart_id = params->restart_id;
   init_params.run_all_compositor_stages_before_draw =
       run_all_compositor_stages_before_draw;
@@ -209,6 +218,7 @@
 
   frame_sink_manager_.reset();
   output_surface_provider_.reset();
+  gpu_memory_buffer_manager_.reset();
   server_shared_bitmap_manager_.reset();
 }
 
diff --git a/components/viz/service/main/viz_compositor_thread_runner_impl.h b/components/viz/service/main/viz_compositor_thread_runner_impl.h
index c839d44..336af7a 100644
--- a/components/viz/service/main/viz_compositor_thread_runner_impl.h
+++ b/components/viz/service/main/viz_compositor_thread_runner_impl.h
@@ -21,8 +21,10 @@
 }  // namespace base
 
 namespace viz {
-class OutputSurfaceProvider;
 class FrameSinkManagerImpl;
+class GmbVideoFramePoolContextProvider;
+class InProcessGpuMemoryBufferManager;
+class OutputSurfaceProvider;
 class ServerSharedBitmapManager;
 
 #if defined(OS_ANDROID)
@@ -62,7 +64,10 @@
 
   // Start variables to be accessed only on |task_runner_|.
   std::unique_ptr<ServerSharedBitmapManager> server_shared_bitmap_manager_;
+  std::unique_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
   std::unique_ptr<OutputSurfaceProvider> output_surface_provider_;
+  std::unique_ptr<GmbVideoFramePoolContextProvider>
+      gmb_video_frame_pool_context_provider_;
   std::unique_ptr<FrameSinkManagerImpl> frame_sink_manager_;
   // End variables to be accessed only on |task_runner_|.
 
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 71230cb..06f49e79 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -66,7 +66,6 @@
 namespace {
 
 // Private WebKit accessibility attributes.
-NSString* const NSAccessibilityBlockQuoteLevelAttribute = @"AXBlockQuoteLevel";
 NSString* const NSAccessibilityDropEffectsAttribute = @"AXDropEffects";
 NSString* const NSAccessibilityEditableAncestorAttribute =
     @"AXEditableAncestor";
@@ -689,7 +688,6 @@
     NSString* attribute;
     NSString* methodName;
   } attributeToMethodNameContainer[] = {
-      {NSAccessibilityBlockQuoteLevelAttribute, @"blockQuoteLevel"},
       {NSAccessibilityChildrenAttribute, @"children"},
       {NSAccessibilityIdentifierChromeAttribute, @"internalId"},
       {NSAccessibilityColumnsAttribute, @"columns"},
@@ -795,22 +793,6 @@
   [super detach];
 }
 
-- (id)blockQuoteLevel {
-  if (![self instanceActive])
-    return nil;
-  // TODO(accessibility) This is for the number of ancestors that are a
-  // <blockquote>, including self, useful for tracking replies to replies etc.
-  // in an email.
-  int level = 0;
-  BrowserAccessibility* ancestor = _owner;
-  while (ancestor) {
-    if (ancestor->GetRole() == ax::mojom::Role::kBlockquote)
-      ++level;
-    ancestor = ancestor->PlatformGetParent();
-  }
-  return @(level);
-}
-
 - (NSArray*)AXChildren {
   return [self children];
 }
@@ -2918,8 +2900,7 @@
 
   // General attributes.
   NSMutableArray* ret = [NSMutableArray
-      arrayWithObjects:NSAccessibilityBlockQuoteLevelAttribute,
-                       NSAccessibilityChildrenAttribute,
+      arrayWithObjects:NSAccessibilityChildrenAttribute,
                        NSAccessibilityIdentifierChromeAttribute,
                        NSAccessibilityDescriptionAttribute,
                        NSAccessibilityElementBusyAttribute,
diff --git a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
index bf34b6b..ee71b15 100644
--- a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
@@ -193,6 +193,10 @@
   RunTypedTest<kMacAttributes>("ax-autocomplete-value.html");
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXBlockQuoteLevel) {
+  RunTypedTest<kMacAttributes>("ax-block-quote-level.html");
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXColumnHeaderUIElements) {
   RunTypedTest<kMacAttributes>("ax-column-header-ui-elements.html");
 }
diff --git a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
index 8a741779..c7f461a8 100644
--- a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
+++ b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
@@ -55,8 +55,8 @@
     return;
   }
 
-  // Unretained() is safe because ForEachFrame() is synchronous.
-  web_contents()->ForEachFrame(base::BindRepeating(
+  // Unretained() is safe because ForEachRenderFrameHost() is synchronous.
+  web_contents()->GetMainFrame()->ForEachRenderFrameHost(base::BindRepeating(
       [](GinJavaBridgeDispatcherHost* host, RenderFrameHost* frame) {
         AgentSchedulingGroupHost& agent_scheduling_group =
             static_cast<RenderFrameHostImpl*>(frame)->GetAgentSchedulingGroup();
@@ -100,8 +100,8 @@
 }
 
 void GinJavaBridgeDispatcherHost::WebContentsDestroyed() {
-  // Unretained() is safe because ForEachFrame() is synchronous.
-  web_contents()->ForEachFrame(base::BindRepeating(
+  // Unretained() is safe because ForEachRenderFrameHost() is synchronous.
+  web_contents()->GetMainFrame()->ForEachRenderFrameHost(base::BindRepeating(
       [](GinJavaBridgeDispatcherHost* host, RenderFrameHost* frame) {
         AgentSchedulingGroupHost& agent_scheduling_group =
             static_cast<RenderFrameHostImpl*>(frame)->GetAgentSchedulingGroup();
diff --git a/content/browser/font_access/font_access_manager_impl_unittest.cc b/content/browser/font_access/font_access_manager_impl_unittest.cc
index df0d8bf1..065cf46c 100644
--- a/content/browser/font_access/font_access_manager_impl_unittest.cc
+++ b/content/browser/font_access/font_access_manager_impl_unittest.cc
@@ -240,10 +240,7 @@
   AutoGrantPermission();
   SetFrameHidden();
 
-  FontEnumerationStatus status;
-  base::ReadOnlySharedMemoryRegion region;
-  std::tie(status, region) = manager_sync_->EnumerateLocalFonts();
-
+  const auto [status, region] = manager_sync_->EnumerateLocalFonts();
   EXPECT_EQ(status, FontEnumerationStatus::kNotVisible);
   EXPECT_FALSE(region.IsValid());
 }
@@ -252,27 +249,25 @@
   AskGrantPermission();
   SimulateUserActivation();
 
-  FontEnumerationStatus status;
-  base::ReadOnlySharedMemoryRegion region;
-  std::tie(status, region) = manager_sync_->EnumerateLocalFonts();
-
-  EXPECT_EQ(status, FontEnumerationStatus::kOk)
-      << "Font Enumeration was successful.";
+  {
+    const auto [status, region] = manager_sync_->EnumerateLocalFonts();
+    EXPECT_EQ(status, FontEnumerationStatus::kOk)
+        << "Font Enumeration was successful.";
+  }
 
   AskGrantPermission();
-  std::tie(status, region) = manager_sync_->EnumerateLocalFonts();
-  EXPECT_EQ(status, FontEnumerationStatus::kNeedsUserActivation)
-      << "User Activation Required.";
+  {
+    const auto [status, region] = manager_sync_->EnumerateLocalFonts();
+    EXPECT_EQ(status, FontEnumerationStatus::kNeedsUserActivation)
+        << "User Activation Required.";
+  }
 }
 
 TEST_F(FontAccessManagerImplTest, PreviouslyGrantedValidateEnumerationBasic) {
   AutoGrantPermission();
   SimulateUserActivation();
 
-  FontEnumerationStatus status;
-  base::ReadOnlySharedMemoryRegion region;
-  std::tie(status, region) = manager_sync_->EnumerateLocalFonts();
-
+  auto [status, region] = manager_sync_->EnumerateLocalFonts();
   EXPECT_EQ(status, FontEnumerationStatus::kOk);
   ValidateFontEnumerationBasic(std::move(status), std::move(region));
 }
@@ -281,20 +276,14 @@
   AskGrantPermission();
   SimulateUserActivation();
 
-  FontEnumerationStatus status;
-  base::ReadOnlySharedMemoryRegion region;
-  std::tie(status, region) = manager_sync_->EnumerateLocalFonts();
-
+  const auto [status, region] = manager_sync_->EnumerateLocalFonts();
   EXPECT_EQ(status, FontEnumerationStatus::kOk);
 }
 
 TEST_F(FontAccessManagerImplTest, EnumerationFailsIfNoActivation) {
   AskGrantPermission();
 
-  FontEnumerationStatus status;
-  base::ReadOnlySharedMemoryRegion region;
-  std::tie(status, region) = manager_sync_->EnumerateLocalFonts();
-
+  const auto [status, region] = manager_sync_->EnumerateLocalFonts();
   EXPECT_EQ(status, FontEnumerationStatus::kNeedsUserActivation);
 }
 
@@ -302,10 +291,7 @@
   AskDenyPermission();
   SimulateUserActivation();
 
-  FontEnumerationStatus status;
-  base::ReadOnlySharedMemoryRegion region;
-  std::tie(status, region) = manager_sync_->EnumerateLocalFonts();
-
+  const auto [status, region] = manager_sync_->EnumerateLocalFonts();
   EXPECT_EQ(status, FontEnumerationStatus::kPermissionDenied);
 }
 
@@ -313,10 +299,7 @@
   AutoDenyPermission();
   SimulateUserActivation();
 
-  FontEnumerationStatus status;
-  base::ReadOnlySharedMemoryRegion region;
-  std::tie(status, region) = manager_sync_->EnumerateLocalFonts();
-
+  const auto [status, region] = manager_sync_->EnumerateLocalFonts();
   EXPECT_EQ(status, FontEnumerationStatus::kPermissionDenied);
 }
 
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc
index fde0681c..1697c16 100644
--- a/content/browser/gpu/gpu_internals_ui.cc
+++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -416,7 +416,11 @@
     }
     display_info.Append(display::BuildGpuInfoEntry(
         "SDR white level in nits",
-        base::NumberToString(display.color_spaces().GetSDRWhiteLevel())));
+        base::NumberToString(display.color_spaces().GetSDRMaxLuminanceNits())));
+    display_info.Append(display::BuildGpuInfoEntry(
+        "HDR relative maximum luminance",
+        base::NumberToString(
+            display.color_spaces().GetHDRMaxLuminanceRelative())));
     display_info.Append(display::BuildGpuInfoEntry(
         "Bits per color component",
         base::NumberToString(display.depth_per_component())));
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 8e34419b..9f8c9a6 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -5898,6 +5898,7 @@
   EXPECT_EQ(iframe_url_1, child->current_url());
   EXPECT_FALSE(child->anonymous());
   EXPECT_FALSE(child->current_frame_host()->anonymous());
+  EXPECT_EQ(false, EvalJs(child->current_frame_host(), "window.anonymous"));
 
   // Changes to the iframe 'anonymous' attribute are propagated to the
   // FrameTreeNode. The RenderFrameHost, however, is updated only on navigation.
@@ -5906,6 +5907,7 @@
              "document.getElementById('test_iframe').anonymous = true;"));
   EXPECT_TRUE(child->anonymous());
   EXPECT_FALSE(child->current_frame_host()->anonymous());
+  EXPECT_EQ(false, EvalJs(child->current_frame_host(), "window.anonymous"));
 
   // Create a grandchild iframe.
   EXPECT_TRUE(ExecJs(
@@ -5922,6 +5924,8 @@
   // RenderFrameHost is not anonymous.
   EXPECT_FALSE(grandchild->anonymous());
   EXPECT_FALSE(grandchild->current_frame_host()->anonymous());
+  EXPECT_EQ(false,
+            EvalJs(grandchild->current_frame_host(), "window.anonymous"));
 
   // Navigate the child iframe same-document. This does not change anything.
   EXPECT_TRUE(ExecJs(main_frame(),
@@ -5931,6 +5935,7 @@
   WaitForLoadStop(web_contents());
   EXPECT_TRUE(child->anonymous());
   EXPECT_FALSE(child->current_frame_host()->anonymous());
+  EXPECT_EQ(false, EvalJs(child->current_frame_host(), "window.anonymous"));
 
   // Now navigate the child iframe cross-document.
   EXPECT_TRUE(ExecJs(
@@ -5939,6 +5944,7 @@
   WaitForLoadStop(web_contents());
   EXPECT_TRUE(child->anonymous());
   EXPECT_TRUE(child->current_frame_host()->anonymous());
+  EXPECT_EQ(true, EvalJs(child->current_frame_host(), "window.anonymous"));
   // An anonymous document has a storage key with a nonce.
   EXPECT_TRUE(child->current_frame_host()->storage_key().nonce().has_value());
   base::UnguessableToken anonymous_nonce =
@@ -5959,6 +5965,10 @@
   // document is anonymous.
   EXPECT_FALSE(grandchild->anonymous());
   EXPECT_TRUE(grandchild->current_frame_host()->anonymous());
+  // TODO(https://crbug.com/1251084): Fill navigation_params->anonymous for the
+  // initial empty document.
+  EXPECT_EQ(false,
+            EvalJs(grandchild->current_frame_host(), "window.anonymous"));
 
   // The storage key's nonce is the same for all anonymous documents in the same
   // page.
@@ -5972,6 +5982,7 @@
                        iframe_url_2)));
   WaitForLoadStop(web_contents());
   EXPECT_TRUE(grandchild->current_frame_host()->anonymous());
+  EXPECT_EQ(true, EvalJs(grandchild->current_frame_host(), "window.anonymous"));
 
   // The storage key's nonce is still the same.
   EXPECT_TRUE(child->current_frame_host()->storage_key().nonce().has_value());
@@ -5985,6 +5996,7 @@
              "document.getElementById('test_iframe').anonymous = false;"));
   EXPECT_FALSE(child->anonymous());
   EXPECT_TRUE(child->current_frame_host()->anonymous());
+  EXPECT_EQ(true, EvalJs(child->current_frame_host(), "window.anonymous"));
   EXPECT_TRUE(child->current_frame_host()->storage_key().nonce().has_value());
   EXPECT_EQ(anonymous_nonce,
             child->current_frame_host()->storage_key().nonce().value());
@@ -6001,6 +6013,10 @@
   FrameTreeNode* grandchild2 = child->child_at(1);
   EXPECT_FALSE(grandchild2->anonymous());
   EXPECT_TRUE(grandchild2->current_frame_host()->anonymous());
+  // TODO(https://crbug.com/1251084): Fill navigation_params->anonymous for the
+  // initial empty document.
+  EXPECT_EQ(false,
+            EvalJs(grandchild2->current_frame_host(), "window.anonymous"));
   EXPECT_TRUE(
       grandchild2->current_frame_host()->storage_key().nonce().has_value());
   EXPECT_EQ(anonymous_nonce,
@@ -6015,6 +6031,7 @@
   WaitForLoadStop(web_contents());
   EXPECT_FALSE(child->anonymous());
   EXPECT_FALSE(child->current_frame_host()->anonymous());
+  EXPECT_EQ(false, EvalJs(child->current_frame_host(), "window.anonymous"));
   EXPECT_FALSE(child->current_frame_host()->storage_key().nonce().has_value());
 
   // Now navigate the whole page away.
@@ -6029,6 +6046,7 @@
   EXPECT_EQ(iframe_url_b, child_b->current_url());
   EXPECT_TRUE(child_b->anonymous());
   EXPECT_TRUE(child_b->current_frame_host()->anonymous());
+  EXPECT_EQ(true, EvalJs(child_b->current_frame_host(), "window.anonymous"));
 
   EXPECT_TRUE(child_b->current_frame_host()->storage_key().nonce().has_value());
   base::UnguessableToken anonymous_nonce_b =
diff --git a/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc b/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc
index d7efb35..335dffd 100644
--- a/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc
+++ b/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc
@@ -25,6 +25,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/renderer_host/dwrite_font_file_util_win.h"
@@ -265,6 +266,9 @@
   // as file handles. The renderer would be unable to open the files directly
   // due to sandbox policy (it would get ERROR_ACCESS_DENIED instead). Passing
   // handles allows the renderer to bypass the restriction and use the fonts.
+  // TODO(jam): if kDWriteFontProxyOnIO is removed also remove the exception
+  // for this class from thread_restrictions.h
+  base::ScopedAllowBlocking allow_io;
   for (const auto& custom_font_path : custom_font_path_set) {
     // Specify FLAG_WIN_EXCLUSIVE_WRITE to prevent base::File from opening the
     // file with FILE_SHARE_WRITE access. FLAG_WIN_EXCLUSIVE_WRITE doesn't
diff --git a/content/browser/renderer_host/frame_tree_browsertest.cc b/content/browser/renderer_host/frame_tree_browsertest.cc
index 654cf4a..62eb8e5 100644
--- a/content/browser/renderer_host/frame_tree_browsertest.cc
+++ b/content/browser/renderer_host/frame_tree_browsertest.cc
@@ -2855,6 +2855,8 @@
                      "document.body.appendChild(f);"));
   EXPECT_EQ(1U, root->child_count());
   EXPECT_FALSE(root->child_at(0)->anonymous());
+  EXPECT_EQ(false, EvalJs(root->child_at(0)->current_frame_host(),
+                          "window.anonymous"));
 
   // Setting the attribute on the iframe element makes the iframe anonymous.
   EXPECT_TRUE(ExecJs(root,
@@ -2863,6 +2865,10 @@
                      "document.body.appendChild(d);"));
   EXPECT_EQ(2U, root->child_count());
   EXPECT_TRUE(root->child_at(1)->anonymous());
+  // TODO(https://crbug.com/1251084): Fill navigation_params->anonymous for the
+  // initial empty document.
+  EXPECT_EQ(false, EvalJs(root->child_at(1)->current_frame_host(),
+                          "window.anonymous"));
 
   // Setting the attribute via javascript works.
   EXPECT_TRUE(ExecJs(root,
@@ -2871,12 +2877,20 @@
                      "document.body.appendChild(g);"));
   EXPECT_EQ(3U, root->child_count());
   EXPECT_TRUE(root->child_at(2)->anonymous());
+  // TODO(https://crbug.com/1251084): Fill navigation_params->anonymous for the
+  // initial empty document.
+  EXPECT_EQ(false, EvalJs(root->child_at(2)->current_frame_host(),
+                          "window.anonymous"));
 
   EXPECT_TRUE(ExecJs(root, "g.anonymous = false;"));
   EXPECT_FALSE(root->child_at(2)->anonymous());
+  EXPECT_EQ(false, EvalJs(root->child_at(2)->current_frame_host(),
+                          "window.anonymous"));
 
   EXPECT_TRUE(ExecJs(root, "g.anonymous = true;"));
   EXPECT_TRUE(root->child_at(2)->anonymous());
+  EXPECT_EQ(false, EvalJs(root->child_at(2)->current_frame_host(),
+                          "window.anonymous"));
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index 6bff2df6..70d01c6 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -3569,7 +3569,7 @@
           std::vector<GURL>() /* early_hints_preloaded_resources */,
           absl::nullopt /* ad_auction_components */,
           // This timestamp will be populated when the commit IPC is sent.
-          base::TimeTicks() /* commit_sent */);
+          base::TimeTicks() /* commit_sent */, false /* anonymous */);
 #if defined(OS_ANDROID)
   if (ValidateDataURLAsString(params.data_url_as_string)) {
     commit_params->data_url_as_string = params.data_url_as_string->data();
diff --git a/content/browser/renderer_host/navigation_entry_impl.cc b/content/browser/renderer_host/navigation_entry_impl.cc
index 867ec70..7716e7b 100644
--- a/content/browser/renderer_host/navigation_entry_impl.cc
+++ b/content/browser/renderer_host/navigation_entry_impl.cc
@@ -932,7 +932,7 @@
           std::vector<GURL>() /* early_hints_preloaded_resources */,
           absl::nullopt /* ad_auction_components */,
           // This timestamp will be populated when the commit IPC is sent.
-          base::TimeTicks() /* commit_sent */);
+          base::TimeTicks() /* commit_sent */, false /* anonymous */);
 #if defined(OS_ANDROID)
   // `data_url_as_string` is saved in NavigationEntry but should only be used by
   // main frames, because loadData* navigations can only happen on the main
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 7cdb114..1e9ff7d0 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -1155,7 +1155,7 @@
           /*early_hints_preloaded_resources=*/
           std::vector<GURL>(), absl::nullopt /* ad_auction_components */,
           // This timestamp will be populated when the commit IPC is sent.
-          base::TimeTicks() /* commit_sent */);
+          base::TimeTicks() /* commit_sent */, false /* anonymous */);
 
   // CreateRendererInitiated() should only be triggered when the navigation is
   // initiated by a frame in the same process.
@@ -1282,7 +1282,7 @@
           std::vector<GURL>() /* early_hints_preloaded_resources */,
           absl::nullopt /* ad_auction_components */,
           // This timestamp will be populated when the commit IPC is sent.
-          base::TimeTicks() /* commit_sent */);
+          base::TimeTicks() /* commit_sent */, false /* anonymous */);
   blink::mojom::BeginNavigationParamsPtr begin_params =
       blink::mojom::BeginNavigationParams::New();
   std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest(
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index a66ed4e..fe5a66d 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -7790,6 +7790,7 @@
   DCHECK(navigation_request);
   DCHECK_EQ(this, navigation_request->GetRenderFrameHost());
 
+  commit_params->anonymous = navigation_request->anonymous();
   bool is_same_document =
       NavigationTypeUtils::IsSameDocument(common_params->navigation_type);
   bool is_mhtml_subframe = navigation_request->IsForMhtmlSubframe();
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 19a38dd..97926be7 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -4074,7 +4074,7 @@
 
   // Whether the current document is loaded inside an anonymous iframe. Updated
   // on every cross-document navigation.
-  bool anonymous_;
+  bool anonymous_ = false;
 
   // The PolicyContainerHost for the current document, containing security
   // policies that apply to it. It should never be null if the RenderFrameHost
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
index 5ed9969..b96c0d36 100644
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -6215,11 +6215,14 @@
   WaitForLoadStop(web_contents());
 
   EXPECT_FALSE(main_rfh->anonymous());
+  EXPECT_EQ(false, EvalJs(main_rfh, "window.anonymous"));
   EXPECT_FALSE(main_rfh->storage_key().nonce().has_value());
 
   EXPECT_EQ(1U, main_rfh->child_count());
   EXPECT_TRUE(main_rfh->child_at(0)->anonymous());
   EXPECT_FALSE(main_rfh->child_at(0)->current_frame_host()->anonymous());
+  EXPECT_EQ(false, EvalJs(main_rfh->child_at(0)->current_frame_host(),
+                          "window.anonymous"));
   EXPECT_FALSE(main_rfh->child_at(0)
                    ->current_frame_host()
                    ->storage_key()
@@ -6324,6 +6327,7 @@
     EXPECT_EQ(1U, main_rfh->child_count());
     RenderFrameHostImpl* iframe = main_rfh->child_at(0)->current_frame_host();
     EXPECT_EQ(anonymous, iframe->anonymous());
+    EXPECT_EQ(anonymous, EvalJs(iframe, "window.anonymous"));
 
     ResetNetworkState();
 
diff --git a/content/browser/worker_host/worker_browsertest.cc b/content/browser/worker_host/worker_browsertest.cc
index 61b55bd0..015bd934 100644
--- a/content/browser/worker_host/worker_browsertest.cc
+++ b/content/browser/worker_host/worker_browsertest.cc
@@ -953,7 +953,7 @@
     EXPECT_EQ(1U, main_rfh->child_count());
     RenderFrameHostImpl* iframe = main_rfh->child_at(0)->current_frame_host();
     EXPECT_EQ(anonymous, iframe->anonymous());
-
+    EXPECT_EQ(anonymous, EvalJs(iframe, "window.anonymous"));
     ResetNetworkState();
 
     GURL worker_url = embedded_test_server()->GetURL("/workers/worker.js");
diff --git a/content/public/browser/browsing_data_filter_builder.h b/content/public/browser/browsing_data_filter_builder.h
index dd10c0f1..86deba3 100644
--- a/content/public/browser/browsing_data_filter_builder.h
+++ b/content/public/browser/browsing_data_filter_builder.h
@@ -6,14 +6,12 @@
 #define CONTENT_PUBLIC_BROWSER_BROWSING_DATA_FILTER_BUILDER_H_
 
 #include <memory>
-#include <ostream>
-#include <set>
 #include <string>
-#include <vector>
 
 #include "base/callback_forward.h"
 #include "content/common/content_export.h"
 #include "net/cookies/cookie_partition_key_collection.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 
 class GURL;
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index 2557875..469b98f8 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -92,7 +92,7 @@
 // Usually, observers should only care about the current RenderViewHost as
 // returned by GetRenderViewHost().
 //
-// TODO(creis, jochen): Hide the fact that there are several RenderViewHosts
+// TODO(creis): Hide the fact that there are several RenderViewHosts
 // from the WebContentsObserver API. http://crbug.com/173325
 class CONTENT_EXPORT WebContentsObserver {
  public:
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index a38f0d9..c456239 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1074,6 +1074,7 @@
 
   navigation_params->origin_agent_cluster = commit_params.origin_agent_cluster;
 
+  navigation_params->anonymous = commit_params.anonymous;
   navigation_params->enabled_client_hints.reserve(
       commit_params.enabled_client_hints.size());
   for (auto enabled_hint : commit_params.enabled_client_hints)
diff --git a/content/test/data/accessibility/mac/attributes/ax-block-quote-level-expected.txt b/content/test/data/accessibility/mac/attributes/ax-block-quote-level-expected.txt
new file mode 100644
index 0000000..028c91e
--- /dev/null
+++ b/content/test/data/accessibility/mac/attributes/ax-block-quote-level-expected.txt
@@ -0,0 +1,2 @@
+level_one.AXBlockQuoteLevel=1
+not_applicable.AXBlockQuoteLevel=0
diff --git a/content/test/data/accessibility/mac/attributes/ax-block-quote-level.html b/content/test/data/accessibility/mac/attributes/ax-block-quote-level.html
new file mode 100644
index 0000000..85c6749
--- /dev/null
+++ b/content/test/data/accessibility/mac/attributes/ax-block-quote-level.html
@@ -0,0 +1,8 @@
+<!--
+@SCRIPT:
+  level_one.AXBlockQuoteLevel
+  not_applicable.AXBlockQuoteLevel
+-->
+<!DOCTYPE html>
+<blockquote id="level_one"></blockquote>
+<div id="not_applicable"></div>
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index e3e5ac8..36ea117 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -436,6 +436,7 @@
 crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/texturespecification/teximage3d_depth.html [ Failure ]
 crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/texturespecification/texstorage2d_format_depth_stencil.html [ Failure ]
+crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/uniformbuffers/random.html [ Failure ]
 
 # Metal AMD ASAN
 crbug.com/1270755 [ mac amd-0x6821 angle-metal passthrough asan ] deqp/functional/gles3/fborender/shared_colorbuffer_01.html [ RetryOnFailure ]
diff --git a/device/bluetooth/OWNERS b/device/bluetooth/OWNERS
index acf50e9..dcf2516 100644
--- a/device/bluetooth/OWNERS
+++ b/device/bluetooth/OWNERS
@@ -1,4 +1,3 @@
-cmumford@google.com
 reillyg@chromium.org
 
 per-file BUILD.gn=*
diff --git a/docs/code_reviews.md b/docs/code_reviews.md
index 59b4ce2..f7d18e0 100644
--- a/docs/code_reviews.md
+++ b/docs/code_reviews.md
@@ -75,8 +75,8 @@
 preferable to have many directories, each with a smaller number of specific
 owners rather than large directories with many owners. Owners should:
 
-  * Demonstrate excellent judgment, teamwork and ability to uphold Chrome
-    development principles.
+  * Demonstrate excellent judgment, teamwork and ability to uphold
+    [Chromium development principles](contributing.md).
 
   * Be already acting as an owner, providing high-quality reviews and design
     feedback.
@@ -95,12 +95,32 @@
     discourage people from sending reviews, including writing "slow" or
     "emeritus" after your name.
 
-The above are guidelines more than they are hard rules, and exceptions are
-okay as long as there is a consensus by the existing owners for them.
-For example, seldom-updated directories may have exceptions to the
-"substantiality" and "recency" requirements. Directories in `third_party`
-should list those most familiar with the library, regardless of how often
-the code is updated.
+Seldom-updated directories may have exceptions to the "substantiality" and
+"recency" requirements.
+
+Directories in `//third_party` should list those most familiar with the
+library, regardless of how often the code is updated.
+
+#### Removal of owners
+
+If a code owner is not meeting the [expectations of
+owners](#expectations-of-owners) listed above for more than one quarter (and
+they are not on a leave during that time), then they may be removed by any
+co-owner or an owner from the parent directory after a 4-week notice, using
+the following process:
+
+  * Upload a change removing the owner and copy all owners in that directory,
+    including the owner in question.
+  * If the affected owner approves the change, it may be landed immediately.
+  * Otherwise, the change author must wait five working days for feedback from
+    the other owners.
+    * After that time has elapsed, if the change has received 3 approvals
+      with no objections from anyone else, the change may be landed.
+    * If the directory does not have 4 owners, then the decision should
+      be escalated to the owners of the parent directory (or directories)
+      as necessary to provide enough of votes.
+    * If there are objections, then the decision should be escalated to
+      the [../CHROME_ENG_REVIEW](//CHROME_ENG_REVIEW) for resolution.
 
 ### OWNERS file details
 
@@ -169,11 +189,11 @@
 ### Owners-Override
 
 Setting the `Owners-Override +1` label will bypass OWNERS enforcement. Active
-[sheriffs](sheriffs.md), Release Program Managers, 
-[Large Scale Changes](#large-scale-changes), 
-[Global Approvers](#global-approvals) reviewers, 
-[Chrome Eng Review members](https://chromium.googlesource.com/chromium/src/+/HEAD/ENG_REVIEW_OWNERS) 
-have this capability. The power to use Owners-Override should be restricted 
+[sheriffs](sheriffs.md), Release Program Managers,
+[Large Scale Changes](#large-scale-changes),
+[Global Approvers](#global-approvals) reviewers,
+[Chrome Eng Review members](https://chromium.googlesource.com/chromium/src/+/HEAD/ENG_REVIEW_OWNERS)
+have this capability. The power to use Owners-Override should be restricted
 as follows:
 
   * Active sheriffs can set Owners-Override only on sheriffing CLs (e.g.,
@@ -186,7 +206,7 @@
     mechanical CLs associated with their API changes. For example,
     //base/OWNERS can set Owners-Override on mechanical CLs associated with
     //base/ API changes.
-  * Chrome Eng Review members can set Owners-Override on any changes to help 
+  * Chrome Eng Review members can set Owners-Override on any changes to help
     with cases that cannot be handled by the above groups and expedite CLs
     when LSC is too heavyweight.. However, please use one of the above groups
     before asking Chrome Eng Review members.
@@ -195,9 +215,9 @@
 Active Sheriffs and Release Program Managers first. If none of them is
 available, please send an email to lsc-owners-override@chromium.org for help.
 
-Note that Owners-Override by itself is not enough on your own CLs. Where this 
-matters is when you are sheriffing. For example, if you want to revert or 
-disable a test, your Owners-Override on the CL is not enough. You need 
+Note that Owners-Override by itself is not enough on your own CLs. Where this
+matters is when you are sheriffing. For example, if you want to revert or
+disable a test, your Owners-Override on the CL is not enough. You need
 another committer to LGTM the CL.
 
 ## Mechanical changes
@@ -208,7 +228,7 @@
 rubberstamp +1s from affected directories' owners. This should only be used for
 mechanical updates to the affected directories.
 
-If you are making one-off CLs that touch many directories and cannot be 
+If you are making one-off CLs that touch many directories and cannot be
 handled by the global approvers, you can ask one of Chrome Eng Review members.
 
 ### Large Scale Changes
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc
index ff682e2..95d85e19 100644
--- a/fuchsia/engine/browser/frame_impl.cc
+++ b/fuchsia/engine/browser/frame_impl.cc
@@ -1274,9 +1274,6 @@
 
 void FrameImpl::ReadyToCommitNavigation(
     content::NavigationHandle* navigation_handle) {
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
   if (!navigation_handle->IsInPrimaryMainFrame() ||
       navigation_handle->IsSameDocument() || navigation_handle->IsErrorPage()) {
     return;
diff --git a/fuchsia/engine/browser/navigation_controller_impl.cc b/fuchsia/engine/browser/navigation_controller_impl.cc
index 09da3a26..3244369d 100644
--- a/fuchsia/engine/browser/navigation_controller_impl.cc
+++ b/fuchsia/engine/browser/navigation_controller_impl.cc
@@ -365,6 +365,10 @@
   if (active_navigation_)
     return;
 
+  // Only allow the primary main frame to transition this state.
+  if (!render_frame_host->IsInPrimaryMainFrame())
+    return;
+
   is_main_document_loaded_ = true;
   OnNavigationEntryChanged();
 }
@@ -379,9 +383,6 @@
 
 void NavigationControllerImpl::DidStartNavigation(
     content::NavigationHandle* navigation_handle) {
-  // TODO(https://crbug.com/1218946): With MPArch there may be multiple main
-  // frames. This caller was converted automatically to the primary main frame
-  // to preserve its semantics. Follow up to confirm correctness.
   if (!navigation_handle->IsInPrimaryMainFrame() ||
       navigation_handle->IsSameDocument()) {
     return;
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_image.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_image.cc
index f1185617..3656afa 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_image.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_image.cc
@@ -41,12 +41,14 @@
     const GpuDriverBugWorkarounds& workarounds,
     const GpuFeatureInfo& gpu_feature_info,
     ImageFactory* image_factory,
-    gl::ProgressReporter* progress_reporter)
+    gl::ProgressReporter* progress_reporter,
+    const bool for_shared_memory_gmbs)
     : SharedImageBackingFactoryGLCommon(gpu_preferences,
                                         workarounds,
                                         gpu_feature_info,
                                         progress_reporter),
-      image_factory_(image_factory) {
+      image_factory_(image_factory),
+      for_shared_memory_gmbs_(for_shared_memory_gmbs) {
   scoped_refptr<gles2::FeatureInfo> feature_info =
       new gles2::FeatureInfo(workarounds, gpu_feature_info);
   feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2,
@@ -259,6 +261,12 @@
   if (thread_safe) {
     return false;
   }
+  // If the GLImage factory is created specifically for SHARED_MEMORY Gmbs,
+  // make sure that it used for that purpose based on flag
+  if ((for_shared_memory_gmbs_ && gmb_type != gfx::SHARED_MEMORY_BUFFER) ||
+      (!for_shared_memory_gmbs_ && gmb_type == gfx::SHARED_MEMORY_BUFFER)) {
+    return false;
+  }
 #if defined(OS_MAC)
   // On macOS, there is no separate interop factory. Any GpuMemoryBuffer-backed
   // image can be used with both OpenGL and Metal
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_image.h b/gpu/command_buffer/service/shared_image_backing_factory_gl_image.h
index 25c52bfb..0cf9425 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_image.h
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_image.h
@@ -35,11 +35,17 @@
 class GPU_GLES2_EXPORT SharedImageBackingFactoryGLImage
     : public SharedImageBackingFactoryGLCommon {
  public:
+  // for_shared_memory_gmbs is a temporary parameter which is used for checking
+  // if gfx::SHARED_MEMORY_BUFFER is supported by the factory.
+  // It is used for migrating GLImage backing, for part that works with
+  // SharedMemory GMB with SharedMemoryBacking and Composite backings, and all
+  // other parts with OzoneBacking and other backings.
   SharedImageBackingFactoryGLImage(const GpuPreferences& gpu_preferences,
                                    const GpuDriverBugWorkarounds& workarounds,
                                    const GpuFeatureInfo& gpu_feature_info,
                                    ImageFactory* image_factory,
-                                   gl::ProgressReporter* progress_reporter);
+                                   gl::ProgressReporter* progress_reporter,
+                                   const bool for_shared_memory_gmbs);
   ~SharedImageBackingFactoryGLImage() override;
 
   // SharedImageBackingFactory implementation.
@@ -115,6 +121,9 @@
   // Factory used to generate GLImages for SCANOUT backings.
   const raw_ptr<ImageFactory> image_factory_ = nullptr;
 
+  // Whether factory is specifically for SHARED_MEMORY Gmbs
+  const bool for_shared_memory_gmbs_ = false;
+
   BufferFormatInfo buffer_format_info_[viz::RESOURCE_FORMAT_MAX + 1];
   GpuMemoryBufferFormatSet gpu_memory_buffer_formats_;
 };
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_image_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_image_unittest.cc
index 5be20ca..ed5be3b2 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_image_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_image_unittest.cc
@@ -107,7 +107,10 @@
     preferences.use_passthrough_cmd_decoder = use_passthrough();
     backing_factory_ = std::make_unique<SharedImageBackingFactoryGLImage>(
         preferences, workarounds, GpuFeatureInfo(), factory,
-        &progress_reporter_);
+        &progress_reporter_, /*for_shared_memory_gmbs=*/false);
+    backing_factory_shmem_ = std::make_unique<SharedImageBackingFactoryGLImage>(
+        preferences, workarounds, GpuFeatureInfo(), factory,
+        &progress_reporter_, /*for_shared_memory_gmbs=*/true);
 
     memory_type_tracker_ = std::make_unique<MemoryTypeTracker>(nullptr);
     shared_image_representation_factory_ =
@@ -137,6 +140,7 @@
   scoped_refptr<gl::GLContext> context_;
   scoped_refptr<SharedContextState> context_state_;
   std::unique_ptr<SharedImageBackingFactoryGLImage> backing_factory_;
+  std::unique_ptr<SharedImageBackingFactoryGLImage> backing_factory_shmem_;
   gles2::MailboxManagerImpl mailbox_manager_;
   std::unique_ptr<SharedImageManager> shared_image_manager_;
   std::unique_ptr<MemoryTypeTracker> memory_type_tracker_;
@@ -771,7 +775,7 @@
   handle.stride = static_cast<int32_t>(
       gfx::RowSizeForBufferFormat(size.width(), format, 0));
 
-  auto backing = backing_factory_->CreateSharedImage(
+  auto backing = backing_factory_shmem_->CreateSharedImage(
       mailbox, kClientId, std::move(handle), format, gfx::BufferPlane::DEFAULT,
       kNullSurfaceHandle, size, color_space, surface_origin, alpha_type, usage);
   if (!can_create_scanout_or_gmb_shared_image(get_format())) {
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
index 73ed228..a25bef2 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
@@ -67,7 +67,7 @@
 
     backing_factory_ = std::make_unique<SharedImageBackingFactoryGLImage>(
         preferences, workarounds, GpuFeatureInfo(), &image_factory_,
-        /*progress_reporter=*/nullptr);
+        /*progress_reporter=*/nullptr, /*for_shared_memory_gmbs=*/false);
 
     memory_type_tracker_ = std::make_unique<MemoryTypeTracker>(nullptr);
     shared_image_representation_factory_ =
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc
index 0a4bf25..3d0cabd 100644
--- a/gpu/command_buffer/service/shared_image_factory.cc
+++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -169,6 +169,33 @@
 #endif
   }
 
+#if defined(OS_WIN)
+  // Only supported for passthrough command decoder and Skia-GL.
+  const bool use_passthrough = gpu_preferences.use_passthrough_cmd_decoder &&
+                               gles2::PassthroughCommandDecoderSupported();
+  const bool is_skia_gl = gr_context_type_ == GrContextType::kGL;
+  // D3D11 device will be null if ANGLE is using the D3D9 backend.
+  // TODO(sunnyps): Should we get the device from SharedContextState instead?
+  auto d3d11_device = gl::QueryD3D11DeviceObjectFromANGLE();
+  if (use_passthrough && is_skia_gl && d3d11_device) {
+    auto d3d_factory = std::make_unique<SharedImageBackingFactoryD3D>(
+        std::move(d3d11_device),
+        shared_image_manager_->dxgi_shared_handle_manager());
+    d3d_backing_factory_ = d3d_factory.get();
+    factories_.push_back(std::move(d3d_factory));
+  }
+#endif  // OS_WIN
+
+  if (use_gl) {
+    auto gl_image_backing_factory =
+        std::make_unique<SharedImageBackingFactoryGLImage>(
+            gpu_preferences, workarounds, gpu_feature_info, image_factory,
+            shared_context_state_ ? shared_context_state_->progress_reporter()
+                                  : nullptr,
+            /*for_shared_memory_gmbs=*/true);
+    factories_.push_back(std::move(gl_image_backing_factory));
+  }
+
   // TODO(ccameron): This block of code should be changed to a switch on
   // |gr_context_type|.
   if (gr_context_type_ == GrContextType::kVulkan) {
@@ -224,29 +251,15 @@
 #endif
   }
 
-#if defined(OS_WIN)
-  // Only supported for passthrough command decoder and Skia-GL.
-  const bool use_passthrough = gpu_preferences.use_passthrough_cmd_decoder &&
-                               gles2::PassthroughCommandDecoderSupported();
-  const bool is_skia_gl = gr_context_type_ == GrContextType::kGL;
-  // D3D11 device will be null if ANGLE is using the D3D9 backend.
-  // TODO(sunnyps): Should we get the device from SharedContextState instead?
-  auto d3d11_device = gl::QueryD3D11DeviceObjectFromANGLE();
-  if (use_passthrough && is_skia_gl && d3d11_device) {
-    auto d3d_factory = std::make_unique<SharedImageBackingFactoryD3D>(
-        std::move(d3d11_device),
-        shared_image_manager_->dxgi_shared_handle_manager());
-    d3d_backing_factory_ = d3d_factory.get();
-    factories_.push_back(std::move(d3d_factory));
-  }
-#endif  // OS_WIN
-
+  // TODO(hitawala): Temporary factory that will be replaced with Ozone and
+  // other backings
   if (use_gl) {
     auto gl_image_backing_factory =
         std::make_unique<SharedImageBackingFactoryGLImage>(
             gpu_preferences, workarounds, gpu_feature_info, image_factory,
             shared_context_state_ ? shared_context_state_->progress_reporter()
-                                  : nullptr);
+                                  : nullptr,
+            /*for_shared_memory_gmbs=*/false);
     factories_.push_back(std::move(gl_image_backing_factory));
   }
 
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 92b9dfb..6d47988 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -12483,6 +12483,12 @@
             }
           }
         }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_text_artifacts"
+          text_artifacts {}
+        }
         history_options {
           use_invocation_timestamp: true
         }
@@ -76601,6 +76607,10 @@
         value: 5
       }
       experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      experiments {
         key: "luci.use_realms"
         value: 100
       }
@@ -76685,6 +76695,10 @@
         value: 5
       }
       experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      experiments {
         key: "luci.use_realms"
         value: 100
       }
@@ -81609,6 +81623,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      experiments {
         key: "luci.use_realms"
         value: 100
       }
@@ -81653,6 +81671,10 @@
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      experiments {
         key: "luci.use_realms"
         value: 100
       }
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index a34addae..33452df 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -5292,6 +5292,11 @@
     short_name: "x64"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Dawn Mac x64 Experimental Release (AMD)"
+    category: "ToT|Mac|AMD"
+    short_name: "exp"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Dawn Mac x64 Release (AMD)"
     category: "ToT|Mac|AMD"
     short_name: "x64"
diff --git a/infra/config/recipes.star b/infra/config/recipes.star
index f46e8fe..13ee954 100644
--- a/infra/config/recipes.star
+++ b/infra/config/recipes.star
@@ -240,6 +240,7 @@
 
 build_recipe(
     name = "recipe:requires_testing_checker",
+    use_python3 = True,
 )
 
 build_recipe(
@@ -259,6 +260,7 @@
 
 build_recipe(
     name = "recipe:tricium_metrics",
+    use_python3 = True,
 )
 
 build_recipe(
@@ -273,4 +275,5 @@
 
 build_recipe(
     name = "recipe:webrtc/chromium_ios",
+    use_python3 = True,
 )
diff --git a/infra/config/subprojects/chromium/ci/chromium.dawn.star b/infra/config/subprojects/chromium/ci/chromium.dawn.star
index cbf5d64c..09439cf 100644
--- a/infra/config/subprojects/chromium/ci/chromium.dawn.star
+++ b/infra/config/subprojects/chromium/ci/chromium.dawn.star
@@ -144,11 +144,10 @@
 
 ci.thin_tester(
     name = "Dawn Mac x64 Experimental Release (AMD)",
-    # Uncomment this entry when this experimental tester is actually in use.
-    # console_view_entry = consoles.console_view_entry(
-    #     category = "ToT|Mac|AMD",
-    #     short_name = "exp",
-    # ),
+    console_view_entry = consoles.console_view_entry(
+        category = "ToT|Mac|AMD",
+        short_name = "exp",
+    ),
     list_view = "chromium.gpu.experimental",
     triggered_by = ["Dawn Mac x64 Builder"],
 )
diff --git a/infra/config/subprojects/chromium/ci/chromium.linux.star b/infra/config/subprojects/chromium/ci/chromium.linux.star
index 55efe99..a8f0245 100644
--- a/infra/config/subprojects/chromium/ci/chromium.linux.star
+++ b/infra/config/subprojects/chromium/ci/chromium.linux.star
@@ -232,6 +232,12 @@
     cq_mirrors_console_view = "mirrors",
     goma_backend = None,
     triggered_by = ["ci/Linux Builder"],
+    # TODO(crbug.com/1249968): Roll this out more broadly.
+    resultdb_bigquery_exports = [
+        resultdb.export_text_artifacts(
+            bq_table = "chrome-luci-data.chromium.ci_text_artifacts",
+        ),
+    ],
 )
 
 ci.builder(
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 755f985d..1162aa5 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -669,15 +669,6 @@
      flag_descriptions::kDefaultWebViewContextMenuName,
      flag_descriptions::kDefaultWebViewContextMenuDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(web::features::kDefaultWebViewContextMenu)},
-    {"send-tab-to-self-when-signed-in",
-     flag_descriptions::kSendTabToSelfWhenSignedInName,
-     flag_descriptions::kSendTabToSelfWhenSignedInDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfWhenSignedIn)},
-    {"send-tab-to-self-manage-devices-link",
-     flag_descriptions::kSendTabToSelfManageDevicesLinkName,
-     flag_descriptions::kSendTabToSelfManageDevicesLinkDescription,
-     flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfManageDevicesLink)},
     {"new-overflow-menu", flag_descriptions::kNewOverflowMenuName,
      flag_descriptions::kNewOverflowMenuDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kNewOverflowMenu)},
@@ -793,6 +784,10 @@
      flag_descriptions::kEnableUnicornAccountSupportDescription,
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(signin::kEnableUnicornAccountSupport)},
+    {"single-cell-content-suggestions",
+     flag_descriptions::kSingleCellContentSuggestionsName,
+     flag_descriptions::kSingleCellContentSuggestionsDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kSingleCellContentSuggestions)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 427f3c7..e4b66ae 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -442,17 +442,6 @@
     "Changes the Clear Browsing Data "
     "UI to display a link to clear search history on My Google Activity.";
 
-const char kSendTabToSelfWhenSignedInName[] = "Send-tab-to-self when signed in";
-const char kSendTabToSelfWhenSignedInDescription[] =
-    "Makes the tab sharing feature also available for users who have \"only\" "
-    "signed-in to their Google Account (as opposed to having enabled Sync).";
-
-const char kSendTabToSelfManageDevicesLinkName[] =
-    "Send-tab-to-self manage devices link";
-const char kSendTabToSelfManageDevicesLinkDescription[] =
-    "Shows a link to manage the user's devices below the device list when "
-    "sharing";
-
 const char kSendUmaOverAnyNetwork[] =
     "Send UMA data over any network available.";
 const char kSendUmaOverAnyNetworkDescription[] =
@@ -463,6 +452,11 @@
     "Adds a Link to Text option in the Edit Menu which generates URLs with a "
     "text fragment.";
 
+const char kSingleCellContentSuggestionsName[] =
+    "Use Single Cell for Content Suggestions";
+const char kSingleCellContentSuggestionsDescription[] =
+    "Uses a single cell for all items in the NTP's content suggestions.";
+
 const char kSingleNtpName[] = "Enable Single NTP";
 const char kSingleNtpDescription[] =
     "When enabled, uses one NTP for all tabs in a Browser";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index b8ea084..0bab78f 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -399,16 +399,6 @@
 extern const char kSearchHistoryLinkIOSName[];
 extern const char kSearchHistoryLinkIOSDescription[];
 
-// Title and description for the flag to enable the send-tab-to-self for a
-// signed-in user (non-syncing).
-extern const char kSendTabToSelfWhenSignedInName[];
-extern const char kSendTabToSelfWhenSignedInDescription[];
-
-// Title and description for the flag to enable the "Manage devices" link in
-// the send-tab-to-self feature UI.
-extern const char kSendTabToSelfManageDevicesLinkName[];
-extern const char kSendTabToSelfManageDevicesLinkDescription[];
-
 // Title and description for the flag to send UMA data over any network.
 extern const char kSendUmaOverAnyNetwork[];
 extern const char kSendUmaOverAnyNetworkDescription[];
@@ -423,6 +413,11 @@
 extern const char kShowAutofillTypePredictionsName[];
 extern const char kShowAutofillTypePredictionsDescription[];
 
+// Title and description for the flag to use one cell for the Content
+// Suggestions
+extern const char kSingleCellContentSuggestionsName[];
+extern const char kSingleCellContentSuggestionsDescription[];
+
 // Title and description for the flag to use one NTP for all tabs in a Browser.
 extern const char kSingleNtpName[];
 extern const char kSingleNtpDescription[];
diff --git a/ios/chrome/browser/providers/BUILD.gn b/ios/chrome/browser/providers/BUILD.gn
index 0c486d0..214ff42c 100644
--- a/ios/chrome/browser/providers/BUILD.gn
+++ b/ios/chrome/browser/providers/BUILD.gn
@@ -41,6 +41,7 @@
 
     # The individual API implementations.
     "//ios/chrome/browser/providers/app_distribution:chromium_app_distribution",
+    "//ios/chrome/browser/providers/app_utils:chromium_app_utils",
     "//ios/chrome/browser/providers/branded_images:chromium_branded_images",
     "//ios/chrome/browser/providers/lens:chromium_lens",
     "//ios/chrome/browser/providers/modals:chromium_modals",
diff --git a/ios/chrome/browser/providers/app_utils/BUILD.gn b/ios/chrome/browser/providers/app_utils/BUILD.gn
new file mode 100644
index 0000000..0d1ba96
--- /dev/null
+++ b/ios/chrome/browser/providers/app_utils/BUILD.gn
@@ -0,0 +1,9 @@
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("chromium_app_utils") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "chromium_app_utils.mm" ]
+  deps = [ "//ios/public/provider/chrome/browser/app_utils:app_utils_api" ]
+}
diff --git a/ios/chrome/browser/providers/app_utils/chromium_app_utils.mm b/ios/chrome/browser/providers/app_utils/chromium_app_utils.mm
new file mode 100644
index 0000000..4352e43
--- /dev/null
+++ b/ios/chrome/browser/providers/app_utils/chromium_app_utils.mm
@@ -0,0 +1,27 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/public/provider/chrome/browser/app_utils/app_utils_api.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace provider {
+
+void Initialize() {
+  // Chromium does not have global state to initialize.
+}
+
+void AppendSwitchesFromExperimentalSettings(
+    NSUserDefaults* experimental_settings,
+    base::CommandLine* command_line) {
+  // Chromium does not have experimental settings.
+}
+
+void AttachBrowserAgents(Browser* browser) {
+  // Chromium does not attach additional browser agents.
+}
+
+}  // namespace provider
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_service_unittest.mm b/ios/chrome/browser/safe_browsing/safe_browsing_service_unittest.mm
index 67612dab..0933eda7 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_service_unittest.mm
+++ b/ios/chrome/browser/safe_browsing/safe_browsing_service_unittest.mm
@@ -465,5 +465,5 @@
   EXPECT_TRUE(safe_browsing_service->GetURLLoaderFactory());
 
   safe_browsing_service->ShutDown();
-  base::RunLoop().RunUntilIdle();
+  task_environment.RunUntilIdle();
 }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h
index 537db04..25e23e3e 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h
@@ -15,6 +15,9 @@
 // Feature to use one NTP for all tabs in a Browser.
 extern const base::Feature kSingleNtp;
 
+// Feature to use one cell for Content Suggestions
+extern const base::Feature kSingleCellContentSuggestions;
+
 // A parameter to indicate whether the native UI is enabled for the discover
 // feed.
 extern const char kDiscoverFeedIsNativeUIEnabled[];
@@ -25,4 +28,7 @@
 // Whether the single ntp feature is enabled.
 bool IsSingleNtpEnabled();
 
+// Whether the single cell content suggestions feature is enabled.
+bool IsSingleCellContentSuggestionsEnabled();
+
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_FEATURE_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm
index abaca32..8b34601 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm
@@ -15,6 +15,10 @@
 // Feature disabled by default.
 const base::Feature kSingleNtp{"SingleNTP", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature disabled by default.
+const base::Feature kSingleCellContentSuggestions{
+    "SingleCellContentSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // A parameter to indicate whether the native UI is enabled for the discover
 // feed.
 const char kDiscoverFeedIsNativeUIEnabled[] = "DiscoverFeedIsNativeUIEnabled";
@@ -26,3 +30,7 @@
 bool IsSingleNtpEnabled() {
   return base::FeatureList::IsEnabled(kSingleNtp);
 }
+
+bool IsSingleCellContentSuggestionsEnabled() {
+  return base::FeatureList::IsEnabled(kSingleCellContentSuggestions);
+}
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index eac9591..55b61ef 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -2914,6 +2914,7 @@
 - (void)showTabSwitcher {
   DCHECK(self.mainCoordinator);
   [self.mainCoordinator setActivePage:self.activePage];
+  [self.mainCoordinator setActiveMode:TabGridModeNormal];
   [self.mainCoordinator showTabGrid];
 }
 
diff --git a/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm b/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm
index 7ea91b4..49ea5607f 100644
--- a/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm
+++ b/ios/chrome/browser/ui/send_tab_to_self/send_tab_to_self_table_view_controller.mm
@@ -159,17 +159,14 @@
         toSectionWithIdentifier:kSectionIdentifierEnumZero];
   }
 
-  if (base::FeatureList::IsEnabled(
-          send_tab_to_self::kSendTabToSelfManageDevicesLink)) {
-    SendTabToSelfManageDevicesItem* manageDevicesItem =
-        [[SendTabToSelfManageDevicesItem alloc]
-            initWithType:ItemTypeManageDevices];
-    manageDevicesItem.accountAvatar = self.accountAvatar;
-    manageDevicesItem.accountEmail = self.accountEmail;
-    manageDevicesItem.delegate = self.delegate;
-    [model addItem:manageDevicesItem
-        toSectionWithIdentifier:kSectionIdentifierEnumZero];
-  }
+  SendTabToSelfManageDevicesItem* manageDevicesItem =
+      [[SendTabToSelfManageDevicesItem alloc]
+          initWithType:ItemTypeManageDevices];
+  manageDevicesItem.accountAvatar = self.accountAvatar;
+  manageDevicesItem.accountEmail = self.accountEmail;
+  manageDevicesItem.delegate = self.delegate;
+  [model addItem:manageDevicesItem
+      toSectionWithIdentifier:kSectionIdentifierEnumZero];
 
   self.sendToDevice =
       [[TableViewTextButtonItem alloc] initWithType:ItemTypeSend];
diff --git a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
index 9fd701b..35d795e 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
@@ -64,11 +64,12 @@
 
 // Returns the GREYElementInteraction* for the item on the password list with
 // the given |matcher|. It scrolls in |direction| if necessary to ensure that
-// the matched item is interactable.
+// the matched item is sufficiently visible, thus interactable.
 GREYElementInteraction* GetInteractionForListItem(id<GREYMatcher> matcher,
                                                   GREYDirection direction) {
   return [[EarlGrey
-      selectElementWithMatcher:grey_allOf(matcher, grey_interactable(), nil)]
+      selectElementWithMatcher:grey_allOf(matcher, grey_sufficientlyVisible(),
+                                          nil)]
          usingSearchAction:grey_scrollInDirection(direction, kScrollAmount)
       onElementWithMatcher:grey_accessibilityID(kPasswordsTableViewId)];
 }
@@ -1237,9 +1238,12 @@
   [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
                                     ReauthenticationResult::kSuccess];
 
-  [[EarlGrey
+  [[[EarlGrey
       selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
                                    IDS_IOS_EXPORT_PASSWORDS)]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown,
+                                                  kScrollAmount)
+      onElementWithMatcher:grey_accessibilityID(kPasswordsTableViewId)]
       performAction:grey_tap()];
 
   [GetInteractionForPasswordsExportConfirmAlert(
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h
index 6f8ae58..9b1e4fe 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h
@@ -28,6 +28,7 @@
 extern NSString* const kTabGridEditSelectAllButtonIdentifier;
 extern NSString* const kTabGridEditAddToButtonIdentifier;
 extern NSString* const kTabGridEditShareButtonIdentifier;
+extern NSString* const kTabGridSearchBarIdentifier;
 
 // All kxxxColor constants are RGB values stored in a Hex integer. These will be
 // converted into UIColors using the UIColorFromRGB() function, from
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.mm
index 18113dc..7464eeb 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.mm
@@ -41,6 +41,7 @@
     @"kTabGridEditAddToButtonIdentifier";
 NSString* const kTabGridEditShareButtonIdentifier =
     @"kTabGridEditShareButtonIdentifier";
+NSString* const kTabGridSearchBarIdentifier = @"kTabGridSearchBarIdentifier";
 
 // The color of the text buttons in the toolbars.
 const int kTabGridToolbarTextButtonColor = 0xFFFFFF;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.h
index 43029e7e..51fd584 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.h
@@ -81,6 +81,9 @@
 // remote tabs.
 - (void)setActivePage:(TabGridPage)page;
 
+// Sets the |mode| as the active one.
+- (void)setActiveMode:(TabGridMode)mode;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_GRID_TAB_GRID_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index 68c8ca5..f1a36d4f 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -284,6 +284,10 @@
   self.baseViewController.activePage = page;
 }
 
+- (void)setActiveMode:(TabGridMode)mode {
+  self.baseViewController.tabGridMode = mode;
+}
+
 - (UIViewController*)activeViewController {
   if (self.bvcContainer) {
     // When installing the thumb strip while the tab grid is opened, there is no
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm
index b32abb1..0c63813 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm
@@ -21,7 +21,7 @@
 // approximately 33 pts between the plus button and the done button.
 const int kIconButtonAdditionalSpace = 20;
 const int kSelectionModeButtonSize = 17;
-const int kSearchBarTrailingSpace = 20;
+const int kSearchBarTrailingSpace = 40;
 }
 
 @interface TabGridTopToolbar () <UIToolbarDelegate>
@@ -227,7 +227,8 @@
   if (![self shouldUseCompactLayout:traitCollection])
     widthModifier = kTabGridSearchBarNonCompactWidthRatioModifier;
 
-  CGFloat cancelWidth = [_selectAllButton.title sizeWithAttributes:nil].width;
+  CGFloat cancelWidth =
+      [_cancelSearchButton.title sizeWithAttributes:nil].width;
   CGFloat barWidth =
       (self.bounds.size.width - kSearchBarTrailingSpace - cancelWidth) *
       kTabGridSearchBarWidthRatio * widthModifier;
@@ -391,6 +392,7 @@
     _searchBar = [[UISearchBar alloc] init];
     _searchBar.placeholder =
         l10n_util::GetNSString(IDS_IOS_TAB_GRID_SEARCHBAR_PLACEHOLDER);
+    _searchBar.accessibilityIdentifier = kTabGridSearchBarIdentifier;
     // Cancel Button for the searchbar doesn't appear in ipadOS. Disable it and
     // create a custom cancel button.
     _searchBar.showsCancelButton = NO;
diff --git a/ios/chrome/browser/url_loading/url_loading_browser_agent.mm b/ios/chrome/browser/url_loading/url_loading_browser_agent.mm
index 6cd37e9..eaf8f2a 100644
--- a/ios/chrome/browser/url_loading/url_loading_browser_agent.mm
+++ b/ios/chrome/browser/url_loading/url_loading_browser_agent.mm
@@ -97,7 +97,7 @@
   if (!net::GetValueForKeyInQuery(url, "crash", &crash_string) ||
       (crash_string == "" || crash_string == "true")) {
     // Induce an intentional crash in the browser process.
-    CHECK(false);
+    CHECK(false) << "User triggered inducebrowsercrashforrealz.";
     // Call another function, so that the above CHECK can't be tail call
     // optimized. This ensures that this method's name will show up in the stack
     // for easier identification.
diff --git a/ios/chrome/test/providers/BUILD.gn b/ios/chrome/test/providers/BUILD.gn
index e886417..e9338821 100644
--- a/ios/chrome/test/providers/BUILD.gn
+++ b/ios/chrome/test/providers/BUILD.gn
@@ -10,6 +10,7 @@
 
     # The individual API implementations.
     "//ios/chrome/test/providers/app_distribution",
+    "//ios/chrome/test/providers/app_utils",
     "//ios/chrome/test/providers/branded_images",
     "//ios/chrome/test/providers/lens",
     "//ios/chrome/test/providers/modals",
diff --git a/ios/chrome/test/providers/app_utils/BUILD.gn b/ios/chrome/test/providers/app_utils/BUILD.gn
new file mode 100644
index 0000000..ea0633d
--- /dev/null
+++ b/ios/chrome/test/providers/app_utils/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("app_utils") {
+  testonly = true
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "test_app_utils.mm" ]
+  deps = [ "//ios/public/provider/chrome/browser/app_utils:app_utils_api" ]
+}
diff --git a/ios/chrome/test/providers/app_utils/test_app_utils.mm b/ios/chrome/test/providers/app_utils/test_app_utils.mm
new file mode 100644
index 0000000..aa676c98
--- /dev/null
+++ b/ios/chrome/test/providers/app_utils/test_app_utils.mm
@@ -0,0 +1,27 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/public/provider/chrome/browser/app_utils/app_utils_api.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace provider {
+
+void Initialize() {
+  // Tests do not have global state to initialize.
+}
+
+void AppendSwitchesFromExperimentalSettings(
+    NSUserDefaults* experimental_settings,
+    base::CommandLine* command_line) {
+  // Tests do not have experimental settings.
+}
+
+void AttachBrowserAgents(Browser* browser) {
+  // Tests do not attach additional browser agents.
+}
+
+}  // namespace provider
diff --git a/ios/public/provider/chrome/browser/BUILD.gn b/ios/public/provider/chrome/browser/BUILD.gn
index 414042f18..d016cba 100644
--- a/ios/public/provider/chrome/browser/BUILD.gn
+++ b/ios/public/provider/chrome/browser/BUILD.gn
@@ -26,6 +26,7 @@
   deps = [
     # The individual APIs.
     "//ios/public/provider/chrome/browser/app_distribution:app_distribution_api",
+    "//ios/public/provider/chrome/browser/app_utils:app_utils_api",
     "//ios/public/provider/chrome/browser/branded_images:branded_images_api",
     "//ios/public/provider/chrome/browser/lens:lens_api",
     "//ios/public/provider/chrome/browser/modals:modals_api",
diff --git a/ios/public/provider/chrome/browser/app_utils/BUILD.gn b/ios/public/provider/chrome/browser/app_utils/BUILD.gn
new file mode 100644
index 0000000..7964ee4
--- /dev/null
+++ b/ios/public/provider/chrome/browser/app_utils/BUILD.gn
@@ -0,0 +1,8 @@
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("app_utils_api") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "app_utils_api.h" ]
+}
diff --git a/ios/public/provider/chrome/browser/app_utils/app_utils_api.h b/ios/public/provider/chrome/browser/app_utils/app_utils_api.h
new file mode 100644
index 0000000..98769caa
--- /dev/null
+++ b/ios/public/provider/chrome/browser/app_utils/app_utils_api.h
@@ -0,0 +1,33 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_APP_UTILS_APP_UTILS_API_H_
+#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_APP_UTILS_APP_UTILS_API_H_
+
+#import <Foundation/Foundation.h>
+
+class Browser;
+
+namespace base {
+class CommandLine;
+}
+
+namespace provider {
+
+// Initializes global provider state. Must be called as soon as possible
+// in the application startup code. It is safe to call it multiple times
+// in unit tests.
+void Initialize();
+
+// Appends additional command-line flags. Called before web startup.
+void AppendSwitchesFromExperimentalSettings(
+    NSUserDefaults* experimental_settings,
+    base::CommandLine* command_line);
+
+// Attaches any embedder-specific browser agents to the given |browser|.
+void AttachBrowserAgents(Browser* browser);
+
+}  // namespace provider
+
+#endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_APP_UTILS_APP_UTILS_API_H_
diff --git a/ios/web/download/download_controller_impl_unittest.mm b/ios/web/download/download_controller_impl_unittest.mm
index 3c034280..73e4b3c 100644
--- a/ios/web/download/download_controller_impl_unittest.mm
+++ b/ios/web/download/download_controller_impl_unittest.mm
@@ -96,14 +96,14 @@
 
   if (@available(iOS 15, *)) {
     WKDownload* fake_download = nil;
-    id<DownloadNativeTaskBridgeReadyDelegate> fake_ready_delegate;
-    FakeNativeTaskBridge* fake_task_bridge_ =
+    id<DownloadNativeTaskBridgeDelegate> fake_delegate = nil;
+    FakeNativeTaskBridge* fake_task_bridge =
         [[FakeNativeTaskBridge alloc] initWithDownload:fake_download
-                                 downloadReadyDelegate:fake_ready_delegate];
+                                              delegate:fake_delegate];
 
     download_controller_->CreateNativeDownloadTask(
         &web_state_, identifier, url, @"POST", kContentDisposition,
-        /*total_bytes=*/-1, kMimeType, fake_task_bridge_);
+        /*total_bytes=*/-1, kMimeType, fake_task_bridge);
 
     ASSERT_EQ(1U, delegate_->alive_download_tasks().size());
     DownloadTask* task = delegate_->alive_download_tasks()[0].second.get();
diff --git a/ios/web/download/download_native_task_bridge.h b/ios/web/download/download_native_task_bridge.h
index 8a2c735..e651542 100644
--- a/ios/web/download/download_native_task_bridge.h
+++ b/ios/web/download/download_native_task_bridge.h
@@ -9,7 +9,7 @@
 
 @class DownloadNativeTaskBridge;
 
-@protocol DownloadNativeTaskBridgeReadyDelegate <NSObject>
+@protocol DownloadNativeTaskBridgeDelegate <NSObject>
 
 // Used to set response url, content length, mimetype and http response headers
 // in CRWWkNavigationHandler so method can interact with WKWebView.
@@ -23,10 +23,9 @@
 // as private instance variables in the implementation file in ios/web/download
 @interface DownloadNativeTaskBridge : NSObject <WKDownloadDelegate>
 
-// Default initializer. |download| and |readyDelegate| must be non-nil.
+// Default initializer. |download| and |delegate| must be non-nil.
 - (instancetype)initWithDownload:(WKDownload*)download
-           downloadReadyDelegate:
-               (id<DownloadNativeTaskBridgeReadyDelegate>)readyDelegate
+                        delegate:(id<DownloadNativeTaskBridgeDelegate>)delegate
     NS_DESIGNATED_INITIALIZER API_AVAILABLE(ios(15));
 
 - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/web/download/download_native_task_bridge.mm b/ios/web/download/download_native_task_bridge.mm
index 34ce7345..6593165 100644
--- a/ios/web/download/download_native_task_bridge.mm
+++ b/ios/web/download/download_native_task_bridge.mm
@@ -12,19 +12,18 @@
 
 @implementation DownloadNativeTaskBridge {
   void (^_startDownloadBlock)(NSURL*);
-  id<DownloadNativeTaskBridgeReadyDelegate> _readyDelegate;
+  id<DownloadNativeTaskBridgeDelegate> _delegate;
   void (^_progressionHandler)();
   void (^_completionHandler)(int error_code);
   BOOL _observingDownloadProgress;
 }
 
 - (instancetype)initWithDownload:(WKDownload*)download
-           downloadReadyDelegate:
-               (id<DownloadNativeTaskBridgeReadyDelegate>)readyDelegate
+                        delegate:(id<DownloadNativeTaskBridgeDelegate>)delegate
     API_AVAILABLE(ios(15)) {
   if ((self = [super init])) {
     _download = download;
-    _readyDelegate = readyDelegate;
+    _delegate = delegate;
     _download.delegate = self;
   }
   return self;
@@ -98,7 +97,7 @@
   _suggestedFilename = suggestedFilename;
   _startDownloadBlock = completionHandler;
 
-  [_readyDelegate onDownloadNativeTaskBridgeReadyForDownload:self];
+  [_delegate onDownloadNativeTaskBridgeReadyForDownload:self];
 }
 
 - (void)download:(WKDownload*)download
diff --git a/ios/web/download/download_native_task_impl_unittest.mm b/ios/web/download/download_native_task_impl_unittest.mm
index 82afc13..fc58920 100644
--- a/ios/web/download/download_native_task_impl_unittest.mm
+++ b/ios/web/download/download_native_task_impl_unittest.mm
@@ -70,8 +70,8 @@
  protected:
   DownloadNativeTaskImplTest()
       : fake_task_bridge_([[FakeNativeTaskBridge alloc]
-                 initWithDownload:fake_download
-            downloadReadyDelegate:fake_ready_delegate]),
+            initWithDownload:fake_download_
+                    delegate:fake_delegate_]),
         task_(std::make_unique<DownloadNativeTaskImpl>(&web_state_,
                                                        GURL(kUrl),
                                                        kHttpMethod,
@@ -88,8 +88,8 @@
   FakeBrowserState browser_state_;
   FakeWebState web_state_;
   testing::StrictMock<FakeDownloadNativeTaskImplDelegate> task_delegate_;
-  WKDownload* fake_download API_AVAILABLE(ios(15)) = nil;
-  id<DownloadNativeTaskBridgeReadyDelegate> fake_ready_delegate;
+  WKDownload* fake_download_ API_AVAILABLE(ios(15)) = nil;
+  id<DownloadNativeTaskBridgeDelegate> fake_delegate_ = nil;
   FakeNativeTaskBridge* fake_task_bridge_;
   std::unique_ptr<DownloadNativeTaskImpl> task_;
   MockDownloadTaskObserver task_observer_;
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index f4afb7f..95f6cff 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -65,7 +65,7 @@
 
 }  // namespace
 
-@interface CRWWKNavigationHandler () <DownloadNativeTaskBridgeReadyDelegate> {
+@interface CRWWKNavigationHandler () <DownloadNativeTaskBridgeDelegate> {
   // Referrer for the current page; does not include the fragment.
   NSString* _currentReferrerString;
 
@@ -1064,7 +1064,7 @@
 
   [_nativeTaskBridges
       addObject:[[DownloadNativeTaskBridge alloc] initWithDownload:WKDownload
-                                             downloadReadyDelegate:self]];
+                                                          delegate:self]];
 }
 
 - (void)onDownloadNativeTaskBridgeReadyForDownload:
diff --git a/ios/web/test/fakes/fake_native_task_bridge.mm b/ios/web/test/fakes/fake_native_task_bridge.mm
index 5d2f51a..66a6c80 100644
--- a/ios/web/test/fakes/fake_native_task_bridge.mm
+++ b/ios/web/test/fakes/fake_native_task_bridge.mm
@@ -16,9 +16,9 @@
 @synthesize suggestedFilename = _suggestedFilename;
 
 - (instancetype)initWithDownload:(WKDownload*)download
-           downloadReadyDelegate:
-               (id<DownloadNativeTaskBridgeReadyDelegate>)ready {
-  if (self = [super initWithDownload:download downloadReadyDelegate:ready]) {
+                        delegate:
+                            (id<DownloadNativeTaskBridgeDelegate>)delegate {
+  if (self = [super initWithDownload:download delegate:delegate]) {
     _calledStartDownloadBlock = NO;
     if (@available(iOS 15, *))
       [self downloadInitialized];
diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h
index aa93dd3..3f37935 100644
--- a/ipc/ipc_channel.h
+++ b/ipc/ipc_channel.h
@@ -29,7 +29,7 @@
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 #include "mojo/public/cpp/bindings/shared_remote.h"
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
 #include <sys/types.h>
 #endif
 
@@ -236,7 +236,7 @@
   static std::string GenerateUniqueRandomChannelID();
 #endif
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   // Sandboxed processes live in a PID namespace, so when sending the IPC hello
   // message from client to server we need to send the PID from the global
   // PID namespace.
diff --git a/ipc/ipc_channel_common.cc b/ipc/ipc_channel_common.cc
index c02a071..fb92806 100644
--- a/ipc/ipc_channel_common.cc
+++ b/ipc/ipc_channel_common.cc
@@ -10,7 +10,7 @@
 
 namespace IPC {
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
 namespace {
 int g_global_pid = 0;
@@ -26,7 +26,7 @@
   return g_global_pid;
 }
 
-#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
 // static
 std::unique_ptr<Channel> Channel::CreateClient(
diff --git a/ipc/ipc_channel_mojo.cc b/ipc/ipc_channel_mojo.cc
index 369e9b31..487b839 100644
--- a/ipc/ipc_channel_mojo.cc
+++ b/ipc/ipc_channel_mojo.cc
@@ -112,15 +112,15 @@
 };
 
 base::ProcessId GetSelfPID() {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   if (int global_pid = Channel::GetGlobalPid())
     return global_pid;
-#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
-#if defined(OS_NACL)
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_NACL)
   return -1;
 #else
   return base::GetCurrentProcId();
-#endif  // defined(OS_NACL)
+#endif  // BUILDFLAG(IS_NACL)
 }
 
 }  // namespace
diff --git a/ipc/ipc_channel_mojo_unittest.cc b/ipc/ipc_channel_mojo_unittest.cc
index e5f5d05..595a4ffa 100644
--- a/ipc/ipc_channel_mojo_unittest.cc
+++ b/ipc/ipc_channel_mojo_unittest.cc
@@ -56,7 +56,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 #include "base/file_descriptor_posix.h"
 #include "ipc/ipc_platform_file_attachment_posix.h"
 #endif
@@ -415,7 +415,7 @@
               GetSendingFileContent());
   }
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   static base::FilePath GetSendingFilePath(const base::FilePath& dir_path) {
     return dir_path.Append("ListenerThatExpectsFile.txt");
   }
@@ -1486,7 +1486,7 @@
   DestroyProxy();
 }
 
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
 // TODO(wez): On Mac we need to set up a MachPortBroker before we can transfer
 // Mach ports (which underpin Sharedmemory on Mac) across IPC.
 
@@ -1610,9 +1610,9 @@
 
   Close();
 }
-#endif  // !defined(OS_APPLE)
+#endif  // !BUILDFLAG(IS_APPLE)
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 
 class ListenerThatExpectsFile : public TestListenerBase {
  public:
@@ -1711,9 +1711,9 @@
   Close();
 }
 
-#endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
 const base::ProcessId kMagicChildId = 54321;
 
@@ -1760,6 +1760,6 @@
   Close();
 }
 
-#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace
diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc
index c37e32c..53505383 100644
--- a/ipc/ipc_channel_proxy.cc
+++ b/ipc/ipc_channel_proxy.cc
@@ -484,7 +484,7 @@
 void ChannelProxy::Init(const IPC::ChannelHandle& channel_handle,
                         Channel::Mode mode,
                         bool create_pipe_now) {
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   // When we are creating a server on POSIX, we need its file descriptor
   // to be created immediately so that it can be accessed and passed
   // to other processes. Forcing it to be created immediately avoids
@@ -492,7 +492,7 @@
   if (mode & Channel::MODE_SERVER_FLAG) {
     create_pipe_now = true;
   }
-#endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   Init(
       ChannelFactory::Create(channel_handle, mode, context_->ipc_task_runner()),
       create_pipe_now);
diff --git a/ipc/ipc_fuzzing_tests.cc b/ipc/ipc_fuzzing_tests.cc
index 96d0a743..c099f2f 100644
--- a/ipc/ipc_fuzzing_tests.cc
+++ b/ipc/ipc_fuzzing_tests.cc
@@ -94,7 +94,7 @@
   EXPECT_FALSE(ReadParam(&m, &iter, &vec));
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #define MAYBE_ReadVectorTooLarge1 DISABLED_ReadVectorTooLarge1
 #else
 #define MAYBE_ReadVectorTooLarge1 ReadVectorTooLarge1
diff --git a/ipc/ipc_listener.h b/ipc/ipc_listener.h
index 426bc32..9517de4 100644
--- a/ipc/ipc_listener.h
+++ b/ipc/ipc_listener.h
@@ -41,7 +41,7 @@
       const std::string& interface_name,
       mojo::ScopedInterfaceEndpointHandle handle) {}
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   // Called on the server side when a channel that listens for connections
   // denies an attempt to connect.
   virtual void OnChannelDenied() {}
diff --git a/ipc/ipc_logging.cc b/ipc/ipc_logging.cc
index 19b293d..9307bb8 100644
--- a/ipc/ipc_logging.cc
+++ b/ipc/ipc_logging.cc
@@ -4,6 +4,8 @@
 
 #include "ipc/ipc_logging.h"
 
+#include "build/build_config.h"
+
 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
 #define IPC_MESSAGE_MACROS_LOG_ENABLED
 #endif
@@ -27,7 +29,7 @@
 #include "ipc/ipc_sender.h"
 #include "ipc/ipc_sync_message.h"
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
 #include <unistd.h>
 #endif
 
@@ -51,7 +53,7 @@
       sender_(nullptr),
       main_thread_(base::ThreadTaskRunnerHandle::Get()),
       consumer_(nullptr) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // getenv triggers an unsafe warning. Simply check how big of a buffer
   // would be needed to fetch the value to see if the enviornment variable is
   // set.
@@ -64,12 +66,12 @@
     if (requiredSize && !strncmp("color", buffer, 6))
       enabled_color_ = true;
   }
-#else  // !defined(OS_WIN)
+#else   // !BUILDFLAG(IS_WIN)
   const char* ipc_logging = getenv("CHROME_IPC_LOGGING");
   bool logging_env_var_set = (ipc_logging != NULL);
   if (ipc_logging && !strcmp(ipc_logging, "color"))
     enabled_color_ = true;
-#endif  //defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
   if (logging_env_var_set) {
     enabled_ = true;
     enabled_on_stderr_ = true;
diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc
index 688bd0fa..d5198af 100644
--- a/ipc/ipc_message.cc
+++ b/ipc/ipc_message.cc
@@ -4,6 +4,8 @@
 
 #include "ipc/ipc_message.h"
 
+#include "build/build_config.h"
+
 // ipc_message.h is a widely included header and its size can impact build time.
 // Try not to raise this limit unless necessary. See
 // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
@@ -22,7 +24,7 @@
 #include "ipc/ipc_message_attachment.h"
 #include "ipc/ipc_message_attachment_set.h"
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
 #include "base/file_descriptor_posix.h"
 #include "ipc/ipc_platform_file_attachment_posix.h"
 #endif
@@ -57,7 +59,7 @@
 Message::Message() : base::Pickle(sizeof(Header)) {
   header()->routing = header()->type = 0;
   header()->flags = GetRefNumUpper24();
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   header()->num_fds = 0;
   header()->pad = 0;
 #endif
@@ -70,7 +72,7 @@
   header()->type = type;
   DCHECK((priority & 0xffffff00) == 0);
   header()->flags = priority | GetRefNumUpper24();
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   header()->num_fds = 0;
   header()->pad = 0;
 #endif
diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h
index 874cbd1..8302cee2 100644
--- a/ipc/ipc_message.h
+++ b/ipc/ipc_message.h
@@ -242,7 +242,7 @@
     int32_t routing;  // ID of the view that this message is destined for
     uint32_t type;    // specifies the user-defined message type
     uint32_t flags;   // specifies control flags for the message
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
     uint16_t num_fds; // the number of descriptors included with this message
     uint16_t pad;     // explicitly initialize this to appease valgrind
 #endif
diff --git a/ipc/ipc_message_attachment.cc b/ipc/ipc_message_attachment.cc
index 38e23e7..cc9a817 100644
--- a/ipc/ipc_message_attachment.cc
+++ b/ipc/ipc_message_attachment.cc
@@ -7,25 +7,26 @@
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
 #include "base/notreached.h"
+#include "build/build_config.h"
 #include "ipc/ipc_mojo_handle_attachment.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 #include <unistd.h>
 
 #include "base/posix/eintr_wrapper.h"
 #include "ipc/ipc_platform_file_attachment_posix.h"
 #endif
 
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
 #include "ipc/mach_port_attachment_mac.h"
 #endif
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "ipc/handle_attachment_win.h"
 #endif
 
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
 #include "ipc/handle_attachment_fuchsia.h"
 #endif
 
@@ -33,13 +34,13 @@
 
 namespace {
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) {
   return attachment->Owns()
              ? base::ScopedFD(attachment->TakePlatformFile())
              : base::ScopedFD(HANDLE_EINTR(dup(attachment->file())));
 }
-#endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 
 }  // namespace
 
@@ -52,7 +53,7 @@
     case Type::MOJO_HANDLE:
       return static_cast<internal::MojoHandleAttachment*>(this)->TakeHandle();
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
     case Type::PLATFORM_FILE: {
       // We dup() the handles in IPC::Message to transmit.
       // IPC::MessageAttachmentSet has intricate lifetime semantics for FDs, so
@@ -65,9 +66,9 @@
       }
       return mojo::WrapPlatformFile(std::move(file));
     }
-#endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
     case Type::MACH_PORT: {
       auto* attachment = static_cast<internal::MachPortAttachmentMac*>(this);
       MojoPlatformHandle platform_handle = {
@@ -81,7 +82,7 @@
       attachment->reset_mach_port_ownership();
       return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle));
     }
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
     case Type::FUCHSIA_HANDLE: {
       auto* attachment = static_cast<internal::HandleAttachmentFuchsia*>(this);
       MojoPlatformHandle platform_handle = {
@@ -94,7 +95,7 @@
       }
       return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle));
     }
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
     case Type::WIN_HANDLE:
       return mojo::WrapPlatformFile(base::win::ScopedHandle(
           static_cast<internal::HandleAttachmentWin*>(this)->Take()));
@@ -119,16 +120,16 @@
   if (unwrap_result != MOJO_RESULT_OK)
     return nullptr;
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   if (type == Type::PLATFORM_FILE) {
     base::PlatformFile file = base::kInvalidPlatformFile;
     if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
       file = static_cast<base::PlatformFile>(platform_handle.value);
     return new internal::PlatformFileAttachment(file);
   }
-#endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
   if (type == Type::MACH_PORT) {
     mach_port_t mach_port = MACH_PORT_NULL;
     if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT)
@@ -136,14 +137,14 @@
     return new internal::MachPortAttachmentMac(
         mach_port, internal::MachPortAttachmentMac::FROM_WIRE);
   }
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
   if (type == Type::FUCHSIA_HANDLE) {
     zx::handle zx_handle;
     if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE)
       zx_handle.reset(static_cast<zx_handle_t>(platform_handle.value));
     return new internal::HandleAttachmentFuchsia(std::move(zx_handle));
   }
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
   if (type == Type::WIN_HANDLE) {
     base::PlatformFile platform_file = base::kInvalidPlatformFile;
     if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE) {
diff --git a/ipc/ipc_message_attachment_set.cc b/ipc/ipc_message_attachment_set.cc
index 24c93a6..ab9fa3e3 100644
--- a/ipc/ipc_message_attachment_set.cc
+++ b/ipc/ipc_message_attachment_set.cc
@@ -62,7 +62,7 @@
 bool MessageAttachmentSet::AddAttachment(
     scoped_refptr<MessageAttachment> attachment,
     size_t* index) {
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   if (attachment->GetType() == MessageAttachment::Type::PLATFORM_FILE &&
       num_descriptors() == kMaxDescriptorsPerMessage) {
     DLOG(WARNING) << "Cannot add file descriptor. MessageAttachmentSet full.";
diff --git a/ipc/ipc_message_attachment_set.h b/ipc/ipc_message_attachment_set.h
index 724b22c..bd30ed3 100644
--- a/ipc/ipc_message_attachment_set.h
+++ b/ipc/ipc_message_attachment_set.h
@@ -60,7 +60,7 @@
   // auto-close.
   void CommitAllDescriptors();
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   // This is the maximum number of descriptors per message. We need to know this
   // because the control message kernel interface has to be given a buffer which
   // is large enough to store all the descriptor numbers. Otherwise the kernel
diff --git a/ipc/ipc_message_attachment_set_posix_unittest.cc b/ipc/ipc_message_attachment_set_posix_unittest.cc
index da20449..59d779f 100644
--- a/ipc/ipc_message_attachment_set_posix_unittest.cc
+++ b/ipc/ipc_message_attachment_set_posix_unittest.cc
@@ -130,7 +130,7 @@
   set->CommitAllDescriptors();
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #define MAYBE_DontClose DISABLED_DontClose
 #else
 #define MAYBE_DontClose DontClose
diff --git a/ipc/ipc_message_unittest.cc b/ipc/ipc_message_unittest.cc
index 8b75c6e..22388c86 100644
--- a/ipc/ipc_message_unittest.cc
+++ b/ipc/ipc_message_unittest.cc
@@ -297,7 +297,7 @@
   EXPECT_TRUE(called_);
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #define MAYBE_OneIntegerWithParam DISABLED_OneIntegerWithParam
 #else
 #define MAYBE_OneIntegerWithParam OneIntegerWithParam
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
index 5d1ed41..40b924b 100644
--- a/ipc/ipc_message_utils.cc
+++ b/ipc/ipc_message_utils.cc
@@ -24,25 +24,25 @@
 #include "ipc/ipc_message_attachment_set.h"
 #include "ipc/ipc_mojo_param_traits.h"
 
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
 #include "ipc/mach_port_mac.h"
 #endif
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include <tchar.h>
 #include "ipc/handle_win.h"
 #include "ipc/ipc_platform_file.h"
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 #include "base/file_descriptor_posix.h"
 #include "ipc/ipc_platform_file_attachment_posix.h"
 #endif
 
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
 #include "base/fuchsia/fuchsia_logging.h"
 #include "ipc/handle_attachment_fuchsia.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "base/android/scoped_hardware_buffer_handle.h"
 #include "ipc/ipc_mojo_handle_attachment.h"
 #include "mojo/public/cpp/system/message_pipe.h"
@@ -57,11 +57,11 @@
 
 template<typename CharType>
 void LogBytes(const std::vector<CharType>& data, std::string* out) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // Windows has a GUI for logging, which can handle arbitrary binary data.
   for (size_t i = 0; i < data.size(); ++i)
     out->push_back(data[i]);
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   // On POSIX, we log to stdout, which we assume can display ASCII.
   static const size_t kMaxBytesToLog = 100;
   for (size_t i = 0; i < std::min(data.size(), kMaxBytesToLog); ++i) {
@@ -351,8 +351,9 @@
   l->append(base::NumberToString(p));
 }
 
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_FUCHSIA) || (defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS))
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_FUCHSIA) ||                                              \
+    (BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_64_BITS))
 void ParamTraits<long>::Log(const param_type& p, std::string* l) {
   l->append(base::NumberToString(p));
 }
@@ -403,7 +404,7 @@
   l->append(base::UTF16ToUTF8(p));
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 bool ParamTraits<std::wstring>::Read(const base::Pickle* m,
                                      base::PickleIterator* iter,
                                      param_type* r) {
@@ -532,7 +533,7 @@
   l->append(json);
 }
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 void ParamTraits<base::FileDescriptor>::Write(base::Pickle* m,
                                               const param_type& p) {
   // This serialization must be kept in sync with
@@ -635,9 +636,9 @@
 void ParamTraits<base::ScopedFD>::Log(const param_type& p, std::string* l) {
   l->append(base::StringPrintf("ScopedFD(%d)", p.get()));
 }
-#endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 void ParamTraits<base::win::ScopedHandle>::Write(base::Pickle* m,
                                                  const param_type& p) {
   const bool valid = p.IsValid();
@@ -672,9 +673,9 @@
                                                std::string* l) {
   l->append(base::StringPrintf("ScopedHandle(%p)", p.Get()));
 }
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
 void ParamTraits<zx::vmo>::Write(base::Pickle* m, const param_type& p) {
   // This serialization must be kept in sync with
   // nacl_message_scanner.cc:WriteHandle().
@@ -765,9 +766,9 @@
 void ParamTraits<zx::channel>::Log(const param_type& p, std::string* l) {
   l->append("ZirconChannel");
 }
-#endif  // defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_FUCHSIA)
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 void ParamTraits<base::android::ScopedHardwareBufferHandle>::Write(
     base::Pickle* m,
     const param_type& p) {
@@ -838,7 +839,7 @@
   l->append(base::StringPrintf("base::android::ScopedHardwareBufferHandle(%p)",
                                p.get()));
 }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
 void ParamTraits<base::ReadOnlySharedMemoryRegion>::Write(base::Pickle* m,
                                                           const param_type& p) {
@@ -936,22 +937,22 @@
   WriteParam(m, static_cast<uint64_t>(p.GetSize()));
   WriteParam(m, p.GetGUID());
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   base::win::ScopedHandle h = const_cast<param_type&>(p).PassPlatformHandle();
   HandleWin handle_win(h.Get());
   WriteParam(m, handle_win);
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
   zx::vmo vmo = const_cast<param_type&>(p).PassPlatformHandle();
   WriteParam(m, vmo);
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
   base::mac::ScopedMachSendRight h =
       const_cast<param_type&>(p).PassPlatformHandle();
   MachPortMac mach_port_mac(h.get());
   WriteParam(m, mach_port_mac);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
   m->WriteAttachment(new internal::PlatformFileAttachment(
       base::ScopedFD(const_cast<param_type&>(p).PassPlatformHandle())));
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
   base::subtle::ScopedFDPair h =
       const_cast<param_type&>(p).PassPlatformHandle();
   m->WriteAttachment(new internal::PlatformFileAttachment(std::move(h.fd)));
@@ -985,26 +986,26 @@
   }
   size_t size = static_cast<size_t>(shm_size);
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   HandleWin handle_win;
   if (!ReadParam(m, iter, &handle_win))
     return false;
   *r = base::subtle::PlatformSharedMemoryRegion::Take(
       base::win::ScopedHandle(handle_win.get_handle()), mode, size, guid);
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
   zx::vmo vmo;
   if (!ReadParam(m, iter, &vmo))
     return false;
   *r = base::subtle::PlatformSharedMemoryRegion::Take(std::move(vmo), mode,
                                                       size, guid);
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
   MachPortMac mach_port_mac;
   if (!ReadParam(m, iter, &mach_port_mac))
     return false;
   *r = base::subtle::PlatformSharedMemoryRegion::Take(
       base::mac::ScopedMachSendRight(mach_port_mac.get_mach_port()), mode, size,
       guid);
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
   scoped_refptr<base::Pickle::Attachment> attachment;
   if (!m->ReadAttachment(iter, &attachment))
     return false;
@@ -1013,7 +1014,7 @@
     return false;
   }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   *r = base::subtle::PlatformSharedMemoryRegion::Take(
       base::ScopedFD(
           static_cast<internal::PlatformFileAttachment*>(attachment.get())
@@ -1041,7 +1042,7 @@
                                    ->TakePlatformFile())
               : base::ScopedFD()),
       mode, size, guid);
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(IS_ANDROID)
 
 #endif
 
@@ -1051,19 +1052,19 @@
 void ParamTraits<base::subtle::PlatformSharedMemoryRegion>::Log(
     const param_type& p,
     std::string* l) {
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
   l->append("Handle: ");
   LogParam(p.GetPlatformHandle()->get(), l);
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
   l->append("Handle: ");
   LogParam(p.GetPlatformHandle(), l);
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
   l->append("Mach port: ");
   LogParam(p.GetPlatformHandle(), l);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
   l->append("FD: ");
   LogParam(p.GetPlatformHandle(), l);
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
   base::subtle::FDPair h = p.GetPlatformHandle();
   l->append("FD: ");
   LogParam(h.fd, l);
@@ -1108,7 +1109,7 @@
   LogParam(static_cast<int>(p), l);
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 void ParamTraits<PlatformFileForTransit>::Write(base::Pickle* m,
                                                 const param_type& p) {
   m->WriteBool(p.IsValid());
@@ -1141,7 +1142,7 @@
                                               std::string* l) {
   LogParam(p.GetHandle(), l);
 }
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
 void ParamTraits<base::FilePath>::Write(base::Pickle* m, const param_type& p) {
   p.WriteToPickle(m);
@@ -1386,7 +1387,7 @@
 }
 
 void ParamTraits<Message>::Write(base::Pickle* m, const Message& p) {
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   // We don't serialize the file descriptors in the nested message, so there
   // better not be any.
   DCHECK(!p.HasAttachments());
@@ -1431,7 +1432,7 @@
   l->append("<IPC::Message>");
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64
 // bit systems. That's why we use the Windows macros to convert to 32 bits.
 void ParamTraits<HANDLE>::Write(base::Pickle* m, const param_type& p) {
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index e7b7634..9419429 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -35,11 +35,11 @@
 #include "ipc/ipc_sync_message.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include "base/android/scoped_hardware_buffer_handle.h"
 #endif
 
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
 #include <lib/zx/channel.h>
 #include <lib/zx/vmo.h>
 #endif
@@ -60,7 +60,7 @@
 
 struct ChannelHandle;
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 class PlatformFileForTransit;
 #endif
 
@@ -204,8 +204,9 @@
 //   3) Android 64 bit and Fuchsia also have int64_t typedef'd to long.
 // Since we want to support Android 32<>64 bit IPC, as long as we don't have
 // these traits for 32 bit ARM then that'll catch any errors.
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
-    defined(OS_FUCHSIA) || (defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS))
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_FUCHSIA) ||                                              \
+    (BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_64_BITS))
 template <>
 struct ParamTraits<long> {
   typedef long param_type;
@@ -341,7 +342,7 @@
   COMPONENT_EXPORT(IPC) static void Log(const param_type& p, std::string* l);
 };
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 template <>
 struct COMPONENT_EXPORT(IPC) ParamTraits<std::wstring> {
   typedef std::wstring param_type;
@@ -542,7 +543,7 @@
   static void Log(const param_type& p, std::string* l);
 };
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 // FileDescriptors may be serialised over IPC channels on POSIX. On the
 // receiving side, the FileDescriptor is a valid duplicate of the file
 // descriptor which was transmitted: *it is not just a copy of the integer like
@@ -578,9 +579,9 @@
   static void Log(const param_type& p, std::string* l);
 };
 
-#endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 template <>
 struct COMPONENT_EXPORT(IPC) ParamTraits<base::win::ScopedHandle> {
   using param_type = base::win::ScopedHandle;
@@ -592,7 +593,7 @@
 };
 #endif
 
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
 template <>
 struct COMPONENT_EXPORT(IPC) ParamTraits<zx::vmo> {
   typedef zx::vmo param_type;
@@ -612,9 +613,9 @@
                    param_type* r);
   static void Log(const param_type& p, std::string* l);
 };
-#endif  // defined(OS_FUCHSIA)
+#endif  // BUILDFLAG(IS_FUCHSIA)
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 template <>
 struct COMPONENT_EXPORT(IPC)
     ParamTraits<base::android::ScopedHardwareBufferHandle> {
@@ -679,7 +680,7 @@
   static void Log(const param_type& p, std::string* l);
 };
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 template <>
 struct COMPONENT_EXPORT(IPC) ParamTraits<PlatformFileForTransit> {
   typedef PlatformFileForTransit param_type;
@@ -689,7 +690,7 @@
                    param_type* r);
   static void Log(const param_type& p, std::string* l);
 };
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
 template <>
 struct COMPONENT_EXPORT(IPC) ParamTraits<base::FilePath> {
@@ -736,12 +737,12 @@
   typedef int Type;
 };
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 template <>
 struct SimilarTypeTraits<HWND> {
   typedef HANDLE Type;
 };
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
 template <>
 struct COMPONENT_EXPORT(IPC) ParamTraits<base::Time> {
@@ -1063,7 +1064,7 @@
 
 // Windows ParamTraits ---------------------------------------------------------
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 template <>
 struct COMPONENT_EXPORT(IPC) ParamTraits<HANDLE> {
   typedef HANDLE param_type;
@@ -1083,7 +1084,7 @@
                    param_type* r);
   static void Log(const param_type& p, std::string* l);
 };
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
 //-----------------------------------------------------------------------------
 // Generic message subclasses
diff --git a/ipc/ipc_message_utils_unittest.cc b/ipc/ipc_message_utils_unittest.cc
index 9a16ced..b69da7e6 100644
--- a/ipc/ipc_message_utils_unittest.cc
+++ b/ipc/ipc_message_utils_unittest.cc
@@ -18,7 +18,7 @@
 #include "ipc/ipc_message.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include <windows.h>
 #endif
 
@@ -235,7 +235,7 @@
   EXPECT_EQ(input, output);
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 TEST(IPCMessageUtilsTest, ScopedHandle) {
   HANDLE raw_dupe_handle;
   ASSERT_TRUE(::DuplicateHandle(::GetCurrentProcess(), ::GetCurrentProcess(),
@@ -251,7 +251,7 @@
   EXPECT_TRUE(ReadParam(&message, &iter, &read_handle));
   EXPECT_TRUE(read_handle.IsValid());
 }
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
 }  // namespace
 }  // namespace IPC
diff --git a/ipc/ipc_perftest_util.cc b/ipc/ipc_perftest_util.cc
index 7d9c701..39a4afc 100644
--- a/ipc/ipc_perftest_util.cc
+++ b/ipc/ipc_perftest_util.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/run_loop.h"
+#include "build/build_config.h"
 #include "ipc/ipc_channel_proxy.h"
 #include "ipc/ipc_perftest_messages.h"
 #include "mojo/core/embedder/embedder.h"
@@ -72,11 +73,11 @@
 
 LockThreadAffinity::LockThreadAffinity(int cpu_number)
     : affinity_set_ok_(false) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   const DWORD_PTR thread_mask = static_cast<DWORD_PTR>(1) << cpu_number;
   old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask);
   affinity_set_ok_ = old_affinity_ != 0;
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   cpu_set_t cpuset;
   CPU_ZERO(&cpuset);
   CPU_SET(cpu_number, &cpuset);
@@ -93,10 +94,10 @@
 LockThreadAffinity::~LockThreadAffinity() {
   if (!affinity_set_ok_)
     return;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   auto set_result = SetThreadAffinityMask(GetCurrentThread(), old_affinity_);
   DCHECK_NE(0u, set_result);
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   auto set_result = sched_setaffinity(0, sizeof(old_cpuset_), &old_cpuset_);
   DCHECK_EQ(0, set_result);
 #endif
diff --git a/ipc/ipc_perftest_util.h b/ipc/ipc_perftest_util.h
index 63812be..0d93632 100644
--- a/ipc/ipc_perftest_util.h
+++ b/ipc/ipc_perftest_util.h
@@ -8,8 +8,9 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "build/build_config.h"
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include <windows.h>
 #endif
 
@@ -27,7 +28,7 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/system/core.h"
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include <windows.h>
 #endif
 
@@ -79,9 +80,9 @@
 
  private:
   bool affinity_set_ok_;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   DWORD_PTR old_affinity_;
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   cpu_set_t old_cpuset_;
 #endif
 };
diff --git a/ipc/ipc_platform_file.cc b/ipc/ipc_platform_file.cc
index 3a8198e..4fafafc8 100644
--- a/ipc/ipc_platform_file.cc
+++ b/ipc/ipc_platform_file.cc
@@ -5,9 +5,9 @@
 #include "build/build_config.h"
 #include "ipc/ipc_platform_file.h"
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include <windows.h>
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 #include <unistd.h>
 
 #include "base/posix/eintr_wrapper.h"
@@ -15,7 +15,7 @@
 
 namespace IPC {
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 PlatformFileForTransit::PlatformFileForTransit() : handle_(nullptr) {}
 
 PlatformFileForTransit::PlatformFileForTransit(HANDLE handle)
@@ -39,11 +39,11 @@
   return handle_ != nullptr;
 }
 
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
 PlatformFileForTransit GetPlatformFileForTransit(base::PlatformFile handle,
                                                  bool close_source_handle) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   HANDLE raw_handle = INVALID_HANDLE_VALUE;
   DWORD options = DUPLICATE_SAME_ACCESS;
   if (close_source_handle)
@@ -55,7 +55,7 @@
   }
 
   return IPC::PlatformFileForTransit(raw_handle);
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   // If asked to close the source, we can simply re-use the source fd instead of
   // dup()ing and close()ing.
   // When we're not closing the source, we need to duplicate the handle and take
diff --git a/ipc/ipc_platform_file.h b/ipc/ipc_platform_file.h
index e174ee8..980f2eee 100644
--- a/ipc/ipc_platform_file.h
+++ b/ipc/ipc_platform_file.h
@@ -10,13 +10,13 @@
 #include "build/build_config.h"
 #include "ipc/ipc_message_support_export.h"
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 #include "base/file_descriptor_posix.h"
 #endif
 
 namespace IPC {
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 class IPC_MESSAGE_SUPPORT_EXPORT PlatformFileForTransit {
  public:
   // Creates an invalid platform file.
@@ -40,32 +40,32 @@
  private:
   HANDLE handle_;
 };
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 typedef base::FileDescriptor PlatformFileForTransit;
 #endif
 
 inline PlatformFileForTransit InvalidPlatformFileForTransit() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   return PlatformFileForTransit();
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   return base::FileDescriptor();
 #endif
 }
 
 inline base::PlatformFile PlatformFileForTransitToPlatformFile(
     const PlatformFileForTransit& transit) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   return transit.GetHandle();
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   return transit.fd;
 #endif
 }
 
 inline base::File PlatformFileForTransitToFile(
     const PlatformFileForTransit& transit) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   return base::File(transit.GetHandle());
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   return base::File(transit.fd);
 #endif
 }
diff --git a/ipc/ipc_sync_channel_unittest.cc b/ipc/ipc_sync_channel_unittest.cc
index cd72979..b3c740f 100644
--- a/ipc/ipc_sync_channel_unittest.cc
+++ b/ipc/ipc_sync_channel_unittest.cc
@@ -326,7 +326,7 @@
   RunTest(workers);
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #define MAYBE_Simple DISABLED_Simple
 #else
 #define MAYBE_Simple Simple
@@ -567,7 +567,7 @@
 
 //------------------------------------------------------------------------------
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #define MAYBE_ChannelDeleteDuringSend DISABLED_ChannelDeleteDuringSend
 #else
 #define MAYBE_ChannelDeleteDuringSend ChannelDeleteDuringSend
@@ -1543,7 +1543,7 @@
   raw_ptr<int> success_;
 };
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #define MAYBE_RestrictedDispatch4WayDeadlock \
   DISABLED_RestrictedDispatch4WayDeadlock
 #else
diff --git a/ipc/ipc_sync_message.h b/ipc/ipc_sync_message.h
index 2d559e6..342e97f 100644
--- a/ipc/ipc_sync_message.h
+++ b/ipc/ipc_sync_message.h
@@ -7,7 +7,9 @@
 
 #include <stdint.h>
 
-#if defined(OS_WIN)
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_WIN)
 #include "base/win/windows_types.h"
 #endif
 
diff --git a/ipc/sync_socket_unittest.cc b/ipc/sync_socket_unittest.cc
index 5aff569..c657f210 100644
--- a/ipc/sync_socket_unittest.cc
+++ b/ipc/sync_socket_unittest.cc
@@ -21,7 +21,7 @@
 #include "ipc/ipc_test_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
 #include "base/file_descriptor_posix.h"
 #endif
 
@@ -36,9 +36,9 @@
 // Message class to pass a base::SyncSocket::Handle to another process.  This
 // is not as easy as it sounds, because of the differences in transferring
 // Windows HANDLEs versus posix file descriptors.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::SyncSocket::Handle)
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
 IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::FileDescriptor)
 #endif
 
@@ -82,17 +82,17 @@
   // This sort of message is sent first, causing the transfer of
   // the handle for the SyncSocket.  This message sends a buffer
   // on the SyncSocket and then sends a response to the client.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) {
     SetHandle(handle);
   }
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
   void OnMsgClassSetHandle(const base::FileDescriptor& fd_struct) {
     SetHandle(fd_struct.fd);
   }
 #else
 # error "What platform?"
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
   void SetHandle(base::SyncSocket::Handle handle) {
     base::SyncSocket sync_socket(handle);
@@ -181,7 +181,7 @@
   // Connect the channel and listener.
   ASSERT_TRUE(ConnectChannel());
   listener.Init(&pair[0], channel());
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // On windows we need to duplicate the handle into the server process.
   BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1].handle(),
                                 client_process().Handle(), &target_handle,
@@ -194,7 +194,7 @@
   // Set up a message to pass the handle to the server.
   base::FileDescriptor filedesc(target_handle, false);
   IPC::Message* msg = new MsgClassSetHandle(filedesc);
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
   EXPECT_TRUE(sender()->Send(msg));
   // Use the current thread as the I/O thread.
   base::RunLoop().Run();
diff --git a/net/cookies/cookie_access_delegate.h b/net/cookies/cookie_access_delegate.h
index 5136c46..5007c3f1 100644
--- a/net/cookies/cookie_access_delegate.h
+++ b/net/cookies/cookie_access_delegate.h
@@ -7,8 +7,10 @@
 
 #include <set>
 
+#include "base/callback_forward.h"
 #include "base/containers/flat_map.h"
 #include "net/base/net_export.h"
+#include "net/base/schemeful_site.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_partition_key.h"
@@ -78,9 +80,13 @@
       const CookieAccessDelegate* delegate,
       const CookiePartitionKey& cookie_partition_key);
 
-  // Returns the First-Party Sets.
-  virtual base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
-  RetrieveFirstPartySets() const = 0;
+  // Computes the First-Party Sets.
+  //
+  // May invoke `callback` either synchronously or asynchronously.
+  virtual void RetrieveFirstPartySets(
+      base::OnceCallback<void(
+          base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>)>
+          callback) const = 0;
 };
 
 }  // namespace net
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index d40384c..0aaef609 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -51,6 +51,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/flat_map.h"
 #include "base/cxx17_backports.h"
 #include "base/feature_list.h"
 #include "base/location.h"
@@ -67,6 +68,7 @@
 #include "net/base/features.h"
 #include "net/base/isolation_info.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/base/schemeful_site.h"
 #include "net/base/url_util.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_constants.h"
@@ -2239,17 +2241,9 @@
   base::UmaHistogramCounts100000("Cookie.Count2", cookies_.size());
 
   if (cookie_access_delegate()) {
-    for (const auto& set : cookie_access_delegate()->RetrieveFirstPartySets()) {
-      int sample = std::accumulate(
-          set.second.begin(), set.second.end(), 0,
-          [this](int acc, const net::SchemefulSite& site) -> int {
-            if (!site.has_registrable_domain_or_host())
-              return acc;
-            return acc + cookies_.count(site.registrable_domain_or_host());
-          });
-      base::UmaHistogramCustomCounts("Cookie.PerFirstPartySetCount", sample, 0,
-                                     4000, 50);
-    }
+    cookie_access_delegate()->RetrieveFirstPartySets(
+        base::BindOnce(&CookieMonster::RecordPeriodicFirstPartySetsStats,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 
   // Can be up to kMaxDomainPurgedKeys.
@@ -2269,6 +2263,21 @@
   return true;
 }
 
+void CookieMonster::RecordPeriodicFirstPartySetsStats(
+    base::flat_map<SchemefulSite, std::set<SchemefulSite>> sets) const {
+  for (const auto& set : sets) {
+    int sample = std::accumulate(
+        set.second.begin(), set.second.end(), 0,
+        [this](int acc, const net::SchemefulSite& site) -> int {
+          if (!site.has_registrable_domain_or_host())
+            return acc;
+          return acc + cookies_.count(site.registrable_domain_or_host());
+        });
+    base::UmaHistogramCustomCounts("Cookie.PerFirstPartySetCount", sample, 0,
+                                   4000, 50);
+  }
+}
+
 void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 10c69ec..1ed421b 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -18,6 +18,7 @@
 
 #include "base/callback_forward.h"
 #include "base/containers/circular_deque.h"
+#include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -25,6 +26,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "net/base/net_export.h"
+#include "net/base/schemeful_site.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_access_delegate.h"
 #include "net/cookies/cookie_constants.h"
@@ -657,6 +659,15 @@
   // cookies. Returns whether stats were recorded.
   bool DoRecordPeriodicStats();
 
+  // Records periodic stats related to First-Party Sets usage. Note that since
+  // First-Party Sets presents a potentially asynchronous interface, these stats
+  // may be collected asynchronously w.r.t. the rest of the stats collected by
+  // `RecordPeriodicStats`.
+  // TODO(https://crbug.com/1266014): don't assume that the sets can all fit in
+  // memory at once.
+  void RecordPeriodicFirstPartySetsStats(
+      base::flat_map<SchemefulSite, std::set<SchemefulSite>> sets) const;
+
   // Defers the callback until the full coookie database has been loaded. If
   // it's already been loaded, runs the callback synchronously.
   void DoCookieCallback(base::OnceClosure callback);
diff --git a/net/cookies/test_cookie_access_delegate.cc b/net/cookies/test_cookie_access_delegate.cc
index 1c3dd36..c46e8b4 100644
--- a/net/cookies/test_cookie_access_delegate.cc
+++ b/net/cookies/test_cookie_access_delegate.cc
@@ -4,7 +4,11 @@
 
 #include "net/cookies/test_cookie_access_delegate.h"
 
+#include <set>
+
+#include "base/callback.h"
 #include "base/containers/contains.h"
+#include "base/containers/flat_map.h"
 #include "net/base/schemeful_site.h"
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_util.h"
@@ -53,9 +57,11 @@
   return absl::nullopt;
 }
 
-base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
-TestCookieAccessDelegate::RetrieveFirstPartySets() const {
-  return first_party_sets_;
+void TestCookieAccessDelegate::RetrieveFirstPartySets(
+    base::OnceCallback<
+        void(base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>)>
+        callback) const {
+  std::move(callback).Run(first_party_sets_);
 }
 
 void TestCookieAccessDelegate::SetExpectationForCookieDomain(
diff --git a/net/cookies/test_cookie_access_delegate.h b/net/cookies/test_cookie_access_delegate.h
index db5ac5cc..e15beff 100644
--- a/net/cookies/test_cookie_access_delegate.h
+++ b/net/cookies/test_cookie_access_delegate.h
@@ -9,7 +9,9 @@
 #include <set>
 #include <string>
 
+#include "base/callback_forward.h"
 #include "base/containers/flat_map.h"
+#include "net/base/schemeful_site.h"
 #include "net/cookies/cookie_access_delegate.h"
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/first_party_set_metadata.h"
@@ -44,8 +46,10 @@
       const std::set<net::SchemefulSite>& party_context) const override;
   absl::optional<net::SchemefulSite> FindFirstPartySetOwner(
       const net::SchemefulSite& site) const override;
-  base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
-  RetrieveFirstPartySets() const override;
+  void RetrieveFirstPartySets(
+      base::OnceCallback<void(
+          base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>)>
+          callback) const override;
 
   // Sets the expected return value for any cookie whose Domain
   // matches |cookie_domain|. Pass the value of |cookie.Domain()| and any
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
index b00abc8..2ae4c86 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
@@ -1184,7 +1184,6 @@
   }
 
   if (cur_version == 13) {
-    const base::TimeTicks start_time = base::TimeTicks::Now();
     sql::Transaction transaction(db());
     if (!transaction.Begin())
       return absl::nullopt;
@@ -1246,8 +1245,6 @@
     meta_table()->SetCompatibleVersionNumber(
         std::min(cur_version, kCompatibleVersionNumber));
     transaction.Commit();
-    base::UmaHistogramTimes("Cookie.TimeDatabaseMigrationToV14",
-                            base::TimeTicks::Now() - start_time);
   }
 
   if (cur_version == 14) {
diff --git a/net/test/cert_test_util.cc b/net/test/cert_test_util.cc
index 9114331..627e689 100644
--- a/net/test/cert_test_util.cc
+++ b/net/test/cert_test_util.cc
@@ -8,9 +8,12 @@
 #include "base/files/file_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "net/cert/ev_root_ca_metadata.h"
+#include "net/cert/pem.h"
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util.h"
 #include "net/test/test_data_directory.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 namespace net {
 
@@ -78,6 +81,22 @@
   return certs_in_file[0];
 }
 
+bssl::UniquePtr<EVP_PKEY> LoadPrivateKeyFromFile(
+    const base::FilePath& key_path) {
+  std::string key_string;
+  if (!base::ReadFileToString(key_path, &key_string))
+    return nullptr;
+  std::vector<std::string> headers;
+  headers.push_back("PRIVATE KEY");
+  PEMTokenizer pem_tokenizer(key_string, headers);
+  if (!pem_tokenizer.GetNext())
+    return nullptr;
+  CBS cbs;
+  CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pem_tokenizer.data().data()),
+           pem_tokenizer.data().size());
+  return bssl::UniquePtr<EVP_PKEY>(EVP_parse_private_key(&cbs));
+}
+
 ScopedTestEVPolicy::ScopedTestEVPolicy(EVRootCAMetadata* ev_root_ca_metadata,
                                        const SHA256HashValue& fingerprint,
                                        const char* policy)
diff --git a/net/test/cert_test_util.h b/net/test/cert_test_util.h
index f5740a7..1bb8d539 100644
--- a/net/test/cert_test_util.h
+++ b/net/test/cert_test_util.h
@@ -98,6 +98,13 @@
     const base::FilePath& certs_dir,
     base::StringPiece cert_file);
 
+// Imports a private key from |key_path|, which should be a PEM file containing
+// a PRIVATE KEY block. Only the first private key found will be returned, if
+// the file contains multiple private keys or other PEM blocks, they will be
+// ignored.
+bssl::UniquePtr<EVP_PKEY> LoadPrivateKeyFromFile(
+    const base::FilePath& key_path);
+
 // ScopedTestEVPolicy causes certificates marked with |policy|, issued from a
 // root with the given fingerprint, to be treated as EV. |policy| is expressed
 // as a string of dotted numbers: i.e. "1.2.3.4".
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index 9f1fc18..25c94d6 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -13,7 +13,6 @@
 #include "base/callback_forward.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_path.h"
-#include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/message_loop/message_pump_type.h"
@@ -35,7 +34,6 @@
 #include "net/base/net_errors.h"
 #include "net/base/port_util.h"
 #include "net/cert/internal/extended_key_usage.h"
-#include "net/cert/pem.h"
 #include "net/cert/test_root_certs.h"
 #include "net/log/net_log_source.h"
 #include "net/socket/next_proto.h"
@@ -56,9 +54,6 @@
 #include "net/test/test_data_directory.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
-#include "third_party/boringssl/src/include/openssl/bytestring.h"
-#include "third_party/boringssl/src/include/openssl/evp.h"
-#include "third_party/boringssl/src/include/openssl/rsa.h"
 #include "url/origin.h"
 
 namespace net {
@@ -222,22 +217,6 @@
   return true;
 }
 
-bssl::UniquePtr<EVP_PKEY> LoadPrivateKeyFromFile(
-    const base::FilePath& key_path) {
-  std::string key_string;
-  if (!base::ReadFileToString(key_path, &key_string))
-    return nullptr;
-  std::vector<std::string> headers;
-  headers.push_back("PRIVATE KEY");
-  PEMTokenizer pem_tokenizer(key_string, headers);
-  if (!pem_tokenizer.GetNext())
-    return nullptr;
-  CBS cbs;
-  CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pem_tokenizer.data().data()),
-           pem_tokenizer.data().size());
-  return bssl::UniquePtr<EVP_PKEY>(EVP_parse_private_key(&cbs));
-}
-
 }  // namespace
 
 EmbeddedTestServerHandle::EmbeddedTestServerHandle(
diff --git a/services/network/cookie_access_delegate_impl.cc b/services/network/cookie_access_delegate_impl.cc
index 3003ca5f..98a00a2 100644
--- a/services/network/cookie_access_delegate_impl.cc
+++ b/services/network/cookie_access_delegate_impl.cc
@@ -4,6 +4,11 @@
 
 #include "services/network/cookie_access_delegate_impl.h"
 
+#include <set>
+
+#include "base/callback_forward.h"
+#include "base/containers/flat_map.h"
+#include "net/base/schemeful_site.h"
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/first_party_set_metadata.h"
@@ -73,11 +78,15 @@
   return first_party_sets_->FindOwner(site);
 }
 
-base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
-CookieAccessDelegateImpl::RetrieveFirstPartySets() const {
-  if (!first_party_sets_)
-    return {};
-  return first_party_sets_->Sets();
+void CookieAccessDelegateImpl::RetrieveFirstPartySets(
+    base::OnceCallback<
+        void(base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>)>
+        callback) const {
+  if (!first_party_sets_) {
+    std::move(callback).Run({});
+    return;
+  }
+  return first_party_sets_->Sets(std::move(callback));
 }
 
 }  // namespace network
diff --git a/services/network/cookie_access_delegate_impl.h b/services/network/cookie_access_delegate_impl.h
index 6a2f951..9f986cbd 100644
--- a/services/network/cookie_access_delegate_impl.h
+++ b/services/network/cookie_access_delegate_impl.h
@@ -5,8 +5,13 @@
 #ifndef SERVICES_NETWORK_COOKIE_ACCESS_DELEGATE_IMPL_H_
 #define SERVICES_NETWORK_COOKIE_ACCESS_DELEGATE_IMPL_H_
 
+#include <set>
+
+#include "base/callback_forward.h"
 #include "base/component_export.h"
+#include "base/containers/flat_map.h"
 #include "base/memory/raw_ptr.h"
+#include "net/base/schemeful_site.h"
 #include "net/cookies/cookie_access_delegate.h"
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/first_party_set_metadata.h"
@@ -55,8 +60,10 @@
       const std::set<net::SchemefulSite>& party_context) const override;
   absl::optional<net::SchemefulSite> FindFirstPartySetOwner(
       const net::SchemefulSite& site) const override;
-  base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
-  RetrieveFirstPartySets() const override;
+  void RetrieveFirstPartySets(
+      base::OnceCallback<void(
+          base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>)>
+          callback) const override;
 
  private:
   const mojom::CookieAccessDelegateType type_;
diff --git a/services/network/first_party_sets/first_party_sets.cc b/services/network/first_party_sets/first_party_sets.cc
index ed94752a..ae589a7 100644
--- a/services/network/first_party_sets/first_party_sets.cc
+++ b/services/network/first_party_sets/first_party_sets.cc
@@ -11,6 +11,7 @@
 
 #include "base/check.h"
 #include "base/containers/contains.h"
+#include "base/containers/flat_map.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
@@ -254,8 +255,10 @@
   return FindOwner(site, /*infer_singleton_sets=*/false);
 }
 
-base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
-FirstPartySets::Sets() const {
+void FirstPartySets::Sets(
+    base::OnceCallback<
+        void(base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>)>
+        callback) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>> sets;
 
@@ -270,7 +273,7 @@
     }
   }
 
-  return sets;
+  std::move(callback).Run(sets);
 }
 
 void FirstPartySets::ApplyManuallySpecifiedSet() {
diff --git a/services/network/first_party_sets/first_party_sets.h b/services/network/first_party_sets/first_party_sets.h
index af9ce173..32dd408 100644
--- a/services/network/first_party_sets/first_party_sets.h
+++ b/services/network/first_party_sets/first_party_sets.h
@@ -75,9 +75,14 @@
     return sets_.size();
   }
 
-  // Returns a mapping from owner to set members. For convenience of iteration,
+  // Computes a mapping from owner to set members. For convenience of iteration,
   // the members of the set includes the owner.
-  base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>> Sets() const;
+  //
+  // `callback` may be called synchronously or asynchronously.
+  void Sets(
+      base::OnceCallback<void(
+          base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>)>
+          callback) const;
 
   // Sets the `raw_persisted_sets_`, which is a JSON-encoded
   // string representation of a map of site -> site.
diff --git a/services/network/first_party_sets/first_party_sets_unittest.cc b/services/network/first_party_sets/first_party_sets_unittest.cc
index 11c7a92..2b533a2b 100644
--- a/services/network/first_party_sets/first_party_sets_unittest.cc
+++ b/services/network/first_party_sets/first_party_sets_unittest.cc
@@ -4,11 +4,14 @@
 
 #include "services/network/first_party_sets/first_party_sets.h"
 
+#include <set>
 #include <string>
 
+#include "base/containers/flat_map.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/json/json_reader.h"
+#include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
@@ -62,6 +65,20 @@
     env_.RunUntilIdle();
   }
 
+  base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>> SetsAndWait()
+      const {
+    base::RunLoop run_loop;
+    base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>> sets;
+    sets_.Sets(base::BindLambdaForTesting(
+        [&](base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
+                result) {
+          sets = result;
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+    return sets;
+  }
+
   FirstPartySets& sets() { return sets_; }
 
   base::test::TaskEnvironment& env() { return env_; }
@@ -86,7 +103,7 @@
   ASSERT_TRUE(base::JSONReader::Read(input));
 
   SetComponentSetsAndWait(input);
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsDisabledTest, ParseV2Format_IgnoresValid) {
@@ -95,12 +112,12 @@
       "[\"https://aaaa.test\"]}";
 
   SetComponentSetsAndWait(input);
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsDisabledTest, SetsManuallySpecified_IgnoresValid) {
   sets().SetManuallySpecifiedSet("https://example.test,https://member.test");
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsDisabledTest, ComputeMetadata_InfersSingletons) {
@@ -156,13 +173,13 @@
 };
 
 TEST_F(FirstPartySetsEnabledTest, Sets_IsEmpty) {
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, IgnoresInvalidFile) {
   sets().ParseAndSet(base::File());
   env().RunUntilIdle();
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 
   const std::string input =
       "{\"owner\": \"https://example.test\",\"members\": "
@@ -171,12 +188,12 @@
   // Subsequent ParseAndSet calls should be ignored, because the instance has
   // already received sets from component updater.
   SetComponentSetsAndWait(input);
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, ParsesJSON) {
   SetComponentSetsAndWait("[]");
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, AcceptsMinimal) {
@@ -189,7 +206,7 @@
 
   SetComponentSetsAndWait(input);
 
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -202,7 +219,7 @@
       "[\"https://aaaa.test\",],}";
 
   SetComponentSetsAndWait(input);
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -226,7 +243,7 @@
   SetComponentSetsAndWait(input);
 
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -245,7 +262,7 @@
 
   SetComponentSetsAndWait(input);
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -272,7 +289,7 @@
   SetComponentSetsAndWait(input);
 
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -298,7 +315,7 @@
 
   // The second call to ParseAndSet should have had no effect.
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -324,7 +341,7 @@
   ASSERT_TRUE(base::JSONReader::Read(input));
   SetComponentSetsAndWait(input);
 
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, OwnerIsMember) {
@@ -343,7 +360,7 @@
   ASSERT_TRUE(base::JSONReader::Read(input));
   SetComponentSetsAndWait(input);
 
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, RepeatedMember) {
@@ -366,36 +383,36 @@
   ASSERT_TRUE(base::JSONReader::Read(input));
   SetComponentSetsAndWait(input);
 
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, SetsManuallySpecified_Invalid_TooSmall) {
   sets().SetManuallySpecifiedSet("https://example.test");
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, SetsManuallySpecified_Invalid_NotOrigins) {
   sets().SetManuallySpecifiedSet("https://example.test,member1");
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, SetsManuallySpecified_Invalid_NotHTTPS) {
   sets().SetManuallySpecifiedSet("https://example.test,http://member1.test");
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest,
        SetsManuallySpecified_Invalid_RegisteredDomain_Owner) {
   sets().SetManuallySpecifiedSet(
       "https://www.example.test..,https://www.member.test");
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest,
        SetsManuallySpecified_Invalid_RegisteredDomain_Member) {
   sets().SetManuallySpecifiedSet(
       "https://www.example.test,https://www.member.test..");
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, SetsManuallySpecified_Valid_EmptyValue) {
@@ -414,7 +431,7 @@
   ASSERT_TRUE(base::JSONReader::Read(existing_sets));
   SetComponentSetsAndWait(existing_sets);
 
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -423,7 +440,7 @@
 
 TEST_F(FirstPartySetsEnabledTest, SetsManuallySpecified_Valid_SingleMember) {
   sets().SetManuallySpecifiedSet("https://example.test,https://member.test");
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -434,7 +451,7 @@
        SetsManuallySpecified_Valid_SingleMember_RegisteredDomain) {
   sets().SetManuallySpecifiedSet(
       "https://www.example.test,https://www.member.test");
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -444,7 +461,7 @@
 TEST_F(FirstPartySetsEnabledTest, SetsManuallySpecified_Valid_MultipleMembers) {
   sets().SetManuallySpecifiedSet(
       "https://example.test,https://member1.test,https://member2.test");
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -455,13 +472,13 @@
 TEST_F(FirstPartySetsEnabledTest,
        SetsManuallySpecified_Valid_OwnerIsOnlyMember) {
   sets().SetManuallySpecifiedSet("https://example.test,https://example.test");
-  EXPECT_THAT(sets().Sets(), IsEmpty());
+  EXPECT_THAT(SetsAndWait(), IsEmpty());
 }
 
 TEST_F(FirstPartySetsEnabledTest, SetsManuallySpecified_Valid_OwnerIsMember) {
   sets().SetManuallySpecifiedSet(
       "https://example.test,https://example.test,https://member1.test");
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -474,7 +491,7 @@
        https://member1.test,
        https://member2.test,
        https://member1.test)");
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -502,7 +519,7 @@
   sets().SetManuallySpecifiedSet(
       "https://example.test,https://member1.test,https://member2.test");
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -533,7 +550,7 @@
   sets().SetManuallySpecifiedSet(
       "https://example.test,https://member1.test,https://member3.test");
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -563,7 +580,7 @@
 
   sets().SetManuallySpecifiedSet("https://example.test,https://member3.test");
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -594,7 +611,7 @@
   sets().SetManuallySpecifiedSet(
       "https://example.test,https://member1.test,https://member2.test");
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -625,7 +642,7 @@
   // If we just erased entries that overlapped with the manually-supplied set,
   // https://foo.test would be left as a singleton set. But since we disallow
   // singleton sets, we ensure that such cases are caught and removed.
-  EXPECT_THAT(sets().Sets(),
+  EXPECT_THAT(SetsAndWait(),
               UnorderedElementsAre(Pair(
                   SerializesTo("https://example.test"),
                   UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -950,7 +967,7 @@
     SetComponentSetsAndWait(input);
 
     CHECK(Value(
-        sets().Sets(),
+        SetsAndWait(),
         UnorderedElementsAre(
             Pair(SerializesTo("https://example.test"),
                  UnorderedElementsAre(SerializesTo("https://example.test"),
@@ -1554,7 +1571,7 @@
 
 TEST_F(PopulatedFirstPartySetsTest, Sets_NonEmpty) {
   EXPECT_THAT(
-      sets().Sets(),
+      SetsAndWait(),
       UnorderedElementsAre(
           Pair(SerializesTo("https://example.test"),
                UnorderedElementsAre(SerializesTo("https://example.test"),
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index 713f0d7..b59c2f5 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -15,7 +15,6 @@
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "mojo/public/mojom/base/values.mojom";
 import "sandbox/policy/mojom/sandbox.mojom";
-import "services/network/public/mojom/cookie_manager.mojom";
 import "services/network/public/mojom/host_resolver.mojom";
 import "services/network/public/mojom/http_raw_headers.mojom";
 import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
diff --git a/services/network/test/test_url_loader_factory.h b/services/network/test/test_url_loader_factory.h
index 43ea25e8..7c14025 100644
--- a/services/network/test/test_url_loader_factory.h
+++ b/services/network/test/test_url_loader_factory.h
@@ -18,7 +18,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
-#include "services/network/public/mojom/url_response_head.mojom-forward.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace network {
 class WeakWrapperSharedURLLoaderFactory;
diff --git a/sql/OWNERS b/sql/OWNERS
index 0717bd0d..bc387a08 100644
--- a/sql/OWNERS
+++ b/sql/OWNERS
@@ -4,5 +4,4 @@
 pwnall@chromium.org
 
 # Secondary:
-cmumford@google.com
 mek@chromium.org
diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc
index 87fd0d56..b2c9ec17 100644
--- a/storage/browser/quota/client_usage_tracker.cc
+++ b/storage/browser/quota/client_usage_tracker.cc
@@ -181,16 +181,6 @@
   return storage_key_usage;
 }
 
-std::set<blink::StorageKey> ClientUsageTracker::GetCachedStorageKeys() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::set<blink::StorageKey> storage_keys;
-  for (const auto& host_and_usage_map : cached_usage_by_host_) {
-    for (const auto& storage_key_and_usage : host_and_usage_map.second)
-      storage_keys.insert(storage_key_and_usage.first);
-  }
-  return storage_keys;
-}
-
 void ClientUsageTracker::SetUsageCacheEnabled(
     const blink::StorageKey& storage_key,
     bool enabled) {
diff --git a/storage/browser/quota/client_usage_tracker.h b/storage/browser/quota/client_usage_tracker.h
index e22336b..f2d72cc 100644
--- a/storage/browser/quota/client_usage_tracker.h
+++ b/storage/browser/quota/client_usage_tracker.h
@@ -70,7 +70,6 @@
   int64_t GetCachedUsage() const;
   std::map<std::string, int64_t> GetCachedHostsUsage() const;
   std::map<blink::StorageKey, int64_t> GetCachedStorageKeysUsage() const;
-  std::set<blink::StorageKey> GetCachedStorageKeys() const;
   bool IsUsageCacheEnabledForStorageKey(
       const blink::StorageKey& storage_key) const;
   void SetUsageCacheEnabled(const blink::StorageKey& storage_key, bool enabled);
diff --git a/storage/browser/quota/quota_manager_impl.cc b/storage/browser/quota/quota_manager_impl.cc
index 83cdc2e..c883e400 100644
--- a/storage/browser/quota/quota_manager_impl.cc
+++ b/storage/browser/quota/quota_manager_impl.cc
@@ -1784,13 +1784,6 @@
   return nullptr;
 }
 
-std::set<StorageKey> QuotaManagerImpl::GetCachedStorageKeys(StorageType type) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  EnsureDatabaseOpened();
-  DCHECK(GetUsageTracker(type));
-  return GetUsageTracker(type)->GetCachedStorageKeys();
-}
-
 void QuotaManagerImpl::NotifyStorageAccessed(const StorageKey& storage_key,
                                              StorageType type,
                                              base::Time access_time) {
@@ -2590,9 +2583,7 @@
     LOG(WARNING) << "Create directory failed for path" << path.value();
     return std::make_tuple<int64_t, int64_t>(0, 0);
   }
-  int64_t total;
-  int64_t available;
-  std::tie(total, available) = get_volume_info_fn(path);
+  const auto [total, available] = get_volume_info_fn(path);
   if (total < 0 || available < 0) {
     LOG(WARNING) << "Unable to get volume info: " << path.value();
     return std::make_tuple<int64_t, int64_t>(0, 0);
diff --git a/storage/browser/quota/quota_manager_impl.h b/storage/browser/quota/quota_manager_impl.h
index cb5ff40..f0f6b421 100644
--- a/storage/browser/quota/quota_manager_impl.h
+++ b/storage/browser/quota/quota_manager_impl.h
@@ -514,11 +514,6 @@
 
   UsageTracker* GetUsageTracker(blink::mojom::StorageType type) const;
 
-  // Extract cached storage keys list from the usage tracker.
-  // (Might return empty list if no storage key is tracked by the tracker.)
-  std::set<blink::StorageKey> GetCachedStorageKeys(
-      blink::mojom::StorageType type);
-
   void DumpQuotaTable(DumpQuotaTableCallback callback);
   void DumpBucketTable(DumpBucketTableCallback callback);
 
diff --git a/storage/browser/quota/quota_manager_unittest.cc b/storage/browser/quota/quota_manager_unittest.cc
index 8fe6be7..9dc62ef 100644
--- a/storage/browser/quota/quota_manager_unittest.cc
+++ b/storage/browser/quota/quota_manager_unittest.cc
@@ -434,10 +434,6 @@
                        weak_factory_.GetWeakPtr()));
   }
 
-  std::set<StorageKey> GetCachedStorageKeys(StorageType type) {
-    return quota_manager_impl_->GetCachedStorageKeys(type);
-  }
-
   void NotifyStorageAccessed(const StorageKey& storage_key, StorageType type) {
     quota_manager_impl_->NotifyStorageAccessed(storage_key, type,
                                                IncrementMockTime());
@@ -2614,45 +2610,6 @@
   EXPECT_EQ(0, usage());
 }
 
-TEST_F(QuotaManagerImplTest, GetCachedStorageKeys) {
-  static const MockStorageKeyData kData[] = {
-      {"http://a.com/", kTemp, 1},
-      {"http://a.com:1/", kTemp, 20},
-      {"http://b.com/", kPerm, 300},
-      {"http://c.com/", kTemp, 4000},
-  };
-  CreateAndRegisterClient(kData, QuotaClientType::kFileSystem,
-                          {blink::mojom::StorageType::kTemporary,
-                           blink::mojom::StorageType::kPersistent});
-
-  // TODO(kinuko): Be careful when we add cache pruner.
-
-  std::set<StorageKey> storage_keys = GetCachedStorageKeys(kTemp);
-  EXPECT_TRUE(storage_keys.empty());
-
-  GetHostUsageWithBreakdown("a.com", kTemp);
-  storage_keys = GetCachedStorageKeys(kTemp);
-  EXPECT_EQ(2U, storage_keys.size());
-
-  GetHostUsageWithBreakdown("b.com", kTemp);
-  storage_keys = GetCachedStorageKeys(kTemp);
-  EXPECT_EQ(2U, storage_keys.size());
-
-  GetHostUsageWithBreakdown("c.com", kTemp);
-  storage_keys = GetCachedStorageKeys(kTemp);
-  EXPECT_EQ(3U, storage_keys.size());
-
-  storage_keys = GetCachedStorageKeys(kPerm);
-  EXPECT_TRUE(storage_keys.empty());
-
-  GetGlobalUsage(kTemp);
-  storage_keys = GetCachedStorageKeys(kTemp);
-  EXPECT_THAT(storage_keys,
-              testing::UnorderedElementsAre(ToStorageKey("http://a.com"),
-                                            ToStorageKey("http://c.com"),
-                                            ToStorageKey("http://a.com:1")));
-}
-
 TEST_F(QuotaManagerImplTest, NotifyAndLRUBucket) {
   static const MockStorageKeyData kData[] = {
       {"http://a.com/", kTemp, 0},
diff --git a/storage/browser/quota/usage_tracker.cc b/storage/browser/quota/usage_tracker.cc
index 8762419..14edf67 100644
--- a/storage/browser/quota/usage_tracker.cc
+++ b/storage/browser/quota/usage_tracker.cc
@@ -154,20 +154,6 @@
   return storage_key_usage;
 }
 
-std::set<blink::StorageKey> UsageTracker::GetCachedStorageKeys() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::set<blink::StorageKey> storage_keys;
-  for (const auto& client_type_and_trackers : client_tracker_map_) {
-    for (const auto& client_tracker : client_type_and_trackers.second) {
-      std::set<blink::StorageKey> client_storage_keys =
-          client_tracker->GetCachedStorageKeys();
-      for (const auto& client_storage_key : client_storage_keys)
-        storage_keys.insert(client_storage_key);
-    }
-  }
-  return storage_keys;
-}
-
 void UsageTracker::SetUsageCacheEnabled(QuotaClientType client_type,
                                         const blink::StorageKey& storage_key,
                                         bool enabled) {
diff --git a/storage/browser/quota/usage_tracker.h b/storage/browser/quota/usage_tracker.h
index 7c300ea..ca50a42 100644
--- a/storage/browser/quota/usage_tracker.h
+++ b/storage/browser/quota/usage_tracker.h
@@ -68,7 +68,6 @@
   int64_t GetCachedUsage() const;
   std::map<std::string, int64_t> GetCachedHostsUsage() const;
   std::map<blink::StorageKey, int64_t> GetCachedStorageKeysUsage() const;
-  std::set<blink::StorageKey> GetCachedStorageKeys() const;
   bool IsWorking() const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return !global_usage_callbacks_.empty() || !host_usage_callbacks_.empty();
diff --git a/styleguide/c++/c++11.md b/styleguide/c++/c++11.md
index 7a41fdf..e83a118 100644
--- a/styleguide/c++/c++11.md
+++ b/styleguide/c++/c++11.md
@@ -480,6 +480,31 @@
 **Notes:**
 *** promo
 See [discussion thread](https://groups.google.com/a/chromium.org/g/cxx/c/op2ePZnjP0w).
+
+### Structured bindings <sup>[allowed]</sup>
+
+```c++
+const auto [x, y] = FuncReturningStdPair();
+```
+
+**Description:** Allows writing `auto [x, y, z] = expr;` where the type of
+`expr` is a tuple-like object, whose elements are bound to the variables `x`,
+`y`, and `z` (which this construct declares). Tuple-like objects include
+`std::tuple`, `std::pair`, `std::array`, and aggregate structures.
+
+**Documentation:**
+[Structured binding declaration](https://en.cppreference.com/w/cpp/language/structured_binding)
+[Explanation of structured binding types](https://jguegant.github.io/blogs/tech/structured-bindings.html)
+
+**Notes:**
+*** promo
+In C++17, structured bindings don't work with lambda captures.
+[C++20 will allow capturing structured bindings by value](https://wg21.link/p1091r3).
+
+This feature forces omitting type names. Its use should follow
+[the guidance around `auto` in Google C++ Style guide](https://google.github.io/styleguide/cppguide.html#Type_deduction).
+
+See [discussion thread](https://groups.google.com/a/chromium.org/g/cxx/c/ExfSorNLNf4).
 ***
 
 ## C++17 Allowed Library Features {#library-allowlist-17}
@@ -506,10 +531,46 @@
 None
 ***
 
+### Type trait variable templates <sup>[tbd]</sup>
+
+```c++
+bool b = std::is_same_v<int, std::int32_t>;
+```
+
+**Description:** Syntactic sugar to provide convenient access to `::value`
+members by simply adding `_v`.
+
+**Documentation:**
+[Type support](https://en.cppreference.com/w/cpp/types)
+
+**Notes:**
+*** promo
+[Discussion thread](Non://groups.google.com/a/chromium.org/g/cxx/c/KEa-0AOGRNY/m/IV_S3_pvAAAJ)
+***
+
 ## C++17 Banned Library Features {#library-blocklist-17}
 
 The following C++17 library features are not allowed in the Chromium codebase.
 
+### std::any <sup>[banned]</sup>
+
+```c++
+std::any x = 5;
+```
+
+**Description:** A type-safe container for single values of any type.
+
+**Documentation:**
+[std::any](https://en.cppreference.com/w/cpp/utility/any)
+
+**Notes:**
+*** promo
+[Discussion thread](https://groups.google.com/a/chromium.org/g/cxx/c/KEa-0AOGRNY/m/IV_S3_pvAAAJ)
+
+Banned since workaround for lack of RTTI isn't compatible with the component
+build ([Bug](https://crbug.com/1096380)). Also see `absl::any`.
+***
+
 ### std::filesystem <sup>[banned]</sup>
 
 ```c++
@@ -719,25 +780,6 @@
 None
 ***
 
-### Structured bindings <sup>[tbd]</sup>
-
-```c++
-const auto [x, y] = FuncReturningStdPair();
-```
-
-**Description:** Allows writing `auto [x, y, z] = expr;` where the type of
-`expr` is a tuple-like object, whose elements are bound to the variables `x`,
-`y`, and `z` (which this construct declares). Tuple-like objects include
-`std::tuple`, `std::pair`, `std::array`, and aggregate structures.
-
-**Documentation:**
-[Structured binding declaration](https://en.cppreference.com/w/cpp/language/structured_binding)
-
-**Notes:**
-*** promo
-None
-***
-
 ### UTF-8 character literals <sup>[tbd]</sup>
 
 ```c++
@@ -875,22 +917,6 @@
 See also `absl::optional`.
 ***
 
-### std::any <sup>[tbd]</sup>
-
-```c++
-std::any x = 5;
-```
-
-**Description:** A type-safe container for single values of any type.
-
-**Documentation:**
-[std::any](https://en.cppreference.com/w/cpp/utility/any)
-
-**Notes:**
-*** promo
-See also `absl::any`.
-***
-
 ### std::string_view <sup>[tbd]</sup>
 
 ```c++
@@ -1147,23 +1173,6 @@
 None
 ***
 
-### Type trait variable templates <sup>[tbd]</sup>
-
-```c++
-bool b = std::is_same_v<int, std::int32_t>;
-```
-
-**Description:** Syntactic sugar to provide convenient access to `::value`
-members by simply adding `_v`.
-
-**Documentation:**
-[Type support](https://en.cppreference.com/w/cpp/types)
-
-**Notes:**
-*** promo
-None
-***
-
 ### std::is_swappable <sup>[tbd]</sup>
 
 ```c++
@@ -1638,7 +1647,7 @@
 **Notes:**
 *** promo
 Banned since workaround for lack of RTTI isn't compatible with the component
-build. ([Bug](https://crbug.com/1096380))
+build ([Bug](https://crbug.com/1096380)). Also see `std::any`.
 ***
 
 ### Command line flags <sup>[banned]</sup>
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index fd949888..f993e7da 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -1924,7 +1924,7 @@
           "has_native_resultdb_integration": true
         },
         "swarming": {},
-        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && \"dep:lacros_unstable\")",
+        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
         "test_id_prefix": "ninja://chromeos/lacros:lacros_all_tast_tests/",
         "timeout_sec": 10800
@@ -1939,7 +1939,7 @@
           "has_native_resultdb_integration": true
         },
         "swarming": {},
-        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && \"dep:lacros_unstable\")",
+        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
         "test_id_prefix": "ninja://chromeos/lacros:lacros_all_tast_tests/",
         "timeout_sec": 10800
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json
index 3dec5a8..84cf730d 100644
--- a/testing/buildbot/chromium.dawn.json
+++ b/testing/buildbot/chromium.dawn.json
@@ -1548,23 +1548,17 @@
     ]
   },
   "Dawn Mac x64 Experimental Release (AMD)": {
-    "isolated_scripts": [
+    "gtest_tests": [
       {
         "args": [
-          "noop_sleep",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--exclusive-device-type-preference=discrete,integrated"
         ],
-        "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
           "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "noop_sleep_tests",
-        "should_retry_with_patch": false,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1578,10 +1572,260 @@
             }
           ],
           "expiration": 21600,
-          "idempotent": false,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
+          "--enable-toggles=skip_validation",
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--exclusive-device-type-preference=discrete,integrated"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_skip_validation_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "display_attached": "1",
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-12.0",
+              "pool": "chromium.tests.gpu"
+            }
+          ],
+          "expiration": 21600,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
+          "--enable-backend-validation",
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--exclusive-device-type-preference=discrete,integrated"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_validation_layers_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "display_attached": "1",
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-12.0",
+              "pool": "chromium.tests.gpu"
+            }
+          ],
+          "expiration": 21600,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
+          "--use-wire",
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--exclusive-device-type-preference=discrete,integrated"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_wire_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "display_attached": "1",
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-12.0",
+              "pool": "chromium.tests.gpu"
+            }
+          ],
+          "expiration": 21600,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dawn_end2end_tests",
+        "test_id_prefix": "ninja://third_party/dawn/src/tests:dawn_end2end_tests/"
+      },
+      {
+        "args": [
+          "--use-cmd-decoder=passthrough",
+          "--use-gl=angle",
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "display_attached": "1",
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-12.0",
+              "pool": "chromium.tests.gpu"
+            }
+          ],
+          "expiration": 21600,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "gl_tests",
+        "test_id_prefix": "ninja://gpu:gl_tests/"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "display_attached": "1",
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-12.0",
+              "pool": "chromium.tests.gpu"
+            }
+          ],
+          "expiration": 21600,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gl_unittests",
+        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "--override-steps=1",
+          "--gtest-benchmark-name=dawn_perf_tests",
+          "-v"
+        ],
+        "isolate_name": "dawn_perf_tests",
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "dawn_perf_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "display_attached": "1",
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-12.0",
+              "pool": "chromium.tests.gpu"
+            }
+          ],
+          "expiration": 21600,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://third_party/dawn/src/tests:dawn_perf_tests/"
+      },
+      {
+        "args": [
+          "--initialize-webgpu-adapter-at-startup-timeout-ms=60000",
+          "--flag-specific=webgpu",
+          "--platform=mac-mac11"
+        ],
+        "isolate_name": "webgpu_blink_web_tests",
+        "merge": {
+          "args": [
+            "--verbose"
+          ],
+          "script": "//third_party/blink/tools/merge_web_test_results.py"
+        },
+        "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "display_attached": "1",
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-12.0",
+              "pool": "chromium.tests.gpu"
+            }
+          ],
+          "expiration": 21600,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 4
+        },
+        "test_id_prefix": "ninja://:webgpu_blink_web_tests/"
+      },
+      {
+        "args": [
+          "--initialize-webgpu-adapter-at-startup-timeout-ms=60000",
+          "--flag-specific=webgpu-with-backend-validation",
+          "--timeout-ms=30000",
+          "--platform=mac-mac11"
+        ],
+        "isolate_name": "webgpu_blink_web_tests",
+        "merge": {
+          "args": [
+            "--verbose"
+          ],
+          "script": "//third_party/blink/tools/merge_web_test_results.py"
+        },
+        "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "display_attached": "1",
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac-12.0",
+              "pool": "chromium.tests.gpu"
+            }
+          ],
+          "expiration": 21600,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 4
+        },
+        "test_id_prefix": "ninja://:webgpu_blink_web_tests/"
       }
     ]
   },
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index 2524ee182..8fc24da0 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1230,7 +1230,7 @@
         "cros_img": "kevin-release/R99-14450.0.0",
         "name": "lacros_all_tast_tests_KEVIN_LKGM",
         "swarming": {},
-        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && \"dep:lacros_unstable\")",
+        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
         "test_id_prefix": "ninja://chromeos/lacros:lacros_all_tast_tests/",
         "timeout_sec": 10800
@@ -1241,7 +1241,7 @@
         "cros_img": "hana-release/R99-14450.0.0",
         "name": "lacros_all_tast_tests_HANA_LKGM",
         "swarming": {},
-        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && \"dep:lacros_unstable\")",
+        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
         "test_id_prefix": "ninja://chromeos/lacros:lacros_all_tast_tests/",
         "timeout_sec": 10800
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 70f7dd93..6617f53 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4332,7 +4332,7 @@
     # lacros_skylab_poc
     'lacros_skylab_arm_tests': {
       'lacros_all_tast_tests': {
-        'tast_expr': '("group:mainline" && "dep:lacros" && "dep:lacros_unstable")',
+        'tast_expr': '("group:mainline" && "dep:lacros" && !informational)',
         'timeout_sec': 10800,
       },
       'ozone_unittests': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index c91ea74..0d6c42fd 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2181,11 +2181,9 @@
           'limited_capacity_bot',
           'mac_retina_amd_gpu_experimental',
         ],
-        # Currently the experimental driver is identical to the stable
-        # driver. If it's upgraded, change these test_suites to be the same as
-        # 'Dawn Mac x64 Release (AMD)'.
         'test_suites': {
-          'gpu_telemetry_tests': 'gpu_noop_sleep_telemetry_test',
+          'gtest_tests': 'gpu_dawn_integration_gtests_passthrough',
+          'isolated_scripts': 'gpu_dawn_isolated_scripts',
         },
       },
       'Dawn Mac x64 Experimental Release (Intel)': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 5cde61c..240da74 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2814,6 +2814,21 @@
             ]
         }
     ],
+    "CredentialProviderExtensionPromo": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "CredentialProviderExtensionPromo"
+                    ]
+                }
+            ]
+        }
+    ],
     "CriticalPersistedTabDataV2": [
         {
             "platforms": [
@@ -7362,40 +7377,6 @@
             ]
         }
     ],
-    "SharedHighlightingClankV2": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "SharedHighlightingV2"
-                    ]
-                }
-            ]
-        }
-    ],
-    "SharedHighlightingDesktopV2": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "SharedHighlightingV2"
-                    ]
-                }
-            ]
-        }
-    ],
     "SharedHighlightingIOS": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/navigation/navigation_params.mojom b/third_party/blink/public/mojom/navigation/navigation_params.mojom
index e501ce68..c6f67d1 100644
--- a/third_party/blink/public/mojom/navigation/navigation_params.mojom
+++ b/third_party/blink/public/mojom/navigation/navigation_params.mojom
@@ -489,4 +489,7 @@
 
   // The time the commit was sent from the browser.
   mojo_base.mojom.TimeTicks commit_sent;
+
+  // Whether or not this navigation will commit in an anonymous frame.
+  bool anonymous = false;
 };
diff --git a/third_party/blink/public/web/web_navigation_params.h b/third_party/blink/public/web/web_navigation_params.h
index 9023ed6..74d13e8e2 100644
--- a/third_party/blink/public/web/web_navigation_params.h
+++ b/third_party/blink/public/web/web_navigation_params.h
@@ -444,6 +444,9 @@
   // contains URNs mapped to the ad components returned by the winning bid.
   // Null, otherwise.
   absl::optional<WebVector<WebURL>> ad_auction_components;
+
+  // Whether or not this navigation will commit in an anonymous frame.
+  bool anonymous = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc b/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc
index 6f869fd..035e906 100644
--- a/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc
@@ -13,27 +13,6 @@
 
 namespace bindings {
 
-namespace {
-
-// These tricks will no longer be necessary once Chromium allows use of
-// constexpr if statement (C++17 feature).
-inline bool IsCallbackConstructor(CallbackFunctionBase* callback) {
-  return callback->IsConstructor();
-}
-inline bool IsCallbackConstructor(CallbackInterfaceBase* callback) {
-  NOTREACHED();
-  return false;
-}
-inline bool IsCallbackObjectCallable(CallbackFunctionBase* callback) {
-  NOTREACHED();
-  return callback->CallbackObject()->IsFunction();
-}
-inline bool IsCallbackObjectCallable(CallbackInterfaceBase* callback) {
-  return callback->IsCallbackObjectCallable();
-}
-
-}  // namespace
-
 template <class CallbackBase, CallbackInvokeHelperMode mode>
 bool CallbackInvokeHelper<CallbackBase, mode>::PrepareForCall(
     V8ValueOrScriptWrappableAdapter callback_this) {
@@ -43,9 +22,9 @@
     return Abort();
   }
 
-  if (mode == CallbackInvokeHelperMode::kConstructorCall) {
+  if constexpr (mode == CallbackInvokeHelperMode::kConstructorCall) {
     // step 3. If ! IsConstructor(F) is false, throw a TypeError exception.
-    if (!IsCallbackConstructor(callback_)) {
+    if (!callback_->IsConstructor()) {
       ExceptionState exception_state(isolate, ExceptionState::kExecutionContext,
                                      class_like_name_, property_name_);
       exception_state.ThrowTypeError(
@@ -54,8 +33,9 @@
     }
   }
 
-  if (std::is_same<CallbackBase, CallbackFunctionBase>::value) {
-    if (mode == CallbackInvokeHelperMode::kLegacyTreatNonObjectAsNull) {
+  if constexpr (std::is_same<CallbackBase, CallbackFunctionBase>::value) {
+    if constexpr (mode ==
+                  CallbackInvokeHelperMode::kLegacyTreatNonObjectAsNull) {
       // step 4. If ! IsCallable(F) is false:
       if (!callback_->CallbackObject()->IsFunction()) {
         // step 4.2. Return the result of converting undefined to the callback
@@ -67,8 +47,8 @@
     DCHECK(callback_->CallbackObject()->IsFunction());
     function_ = callback_->CallbackObject().template As<v8::Function>();
   }
-  if (std::is_same<CallbackBase, CallbackInterfaceBase>::value) {
-    if (IsCallbackObjectCallable(callback_)) {
+  if constexpr (std::is_same<CallbackBase, CallbackInterfaceBase>::value) {
+    if (callback_->IsCallbackObjectCallable()) {
       function_ = callback_->CallbackObject().template As<v8::Function>();
     } else {
       // step 10. If ! IsCallable(O) is false, then:
@@ -95,18 +75,20 @@
     }
   }
 
-  if (mode == CallbackInvokeHelperMode::kConstructorCall) {
-    // Do nothing.
-  } else if (std::is_same<CallbackBase, CallbackInterfaceBase>::value &&
-             !IsCallbackObjectCallable(callback_)) {
-    // step 10.5. Set thisArg to O (overriding the provided value).
-    callback_this_ = callback_->CallbackObject();
-  } else if (callback_this.IsEmpty()) {
-    // step 2. If thisArg was not given, let thisArg be undefined.
-    callback_this_ = v8::Undefined(isolate);
-  } else {
-    callback_this_ =
-        callback_this.V8Value(callback_->CallbackRelevantScriptState());
+  if constexpr (mode != CallbackInvokeHelperMode::kConstructorCall) {
+    bool is_callable = true;
+    if constexpr (std::is_same<CallbackBase, CallbackInterfaceBase>::value)
+      is_callable = callback_->IsCallbackObjectCallable();
+    if (!is_callable) {
+      // step 10.5. Set thisArg to O (overriding the provided value).
+      callback_this_ = callback_->CallbackObject();
+    } else if (callback_this.IsEmpty()) {
+      // step 2. If thisArg was not given, let thisArg be undefined.
+      callback_this_ = v8::Undefined(isolate);
+    } else {
+      callback_this_ =
+          callback_this.V8Value(callback_->CallbackRelevantScriptState());
+    }
   }
 
   return true;
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc
index c21c397..27ddb27 100644
--- a/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -30,6 +30,7 @@
 
 #include "third_party/blink/renderer/core/css/element_rule_collector.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/core/css/cascade_layer_map.h"
 #include "third_party/blink/renderer/core/css/container_query_evaluator.h"
 #include "third_party/blink/renderer/core/css/css_import_rule.h"
@@ -49,6 +50,7 @@
 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/html/html_document.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 
 namespace blink {
@@ -331,6 +333,22 @@
   INCREMENT_STYLE_STATS_COUNTER(style_engine, rules_matched, matched);
 }
 
+namespace {
+
+base::span<const Attribute> GetAttributes(const Element& element,
+                                          bool need_style_synchronized) {
+  if (need_style_synchronized) {
+    const AttributeCollection collection = element.Attributes();
+    return {collection.data(), collection.size()};
+  } else {
+    const AttributeCollection collection =
+        element.AttributesWithoutStyleUpdate();
+    return {collection.data(), collection.size()};
+  }
+}
+
+}  // namespace
+
 DISABLE_CFI_PERF
 void ElementRuleCollector::CollectMatchingRules(
     const MatchRequest& match_request) {
@@ -377,6 +395,61 @@
     }
   }
 
+  // Collect rules from attribute selector buckets, if we have any.
+  if (match_request.rule_set->HasAnyAttrRules()) {
+    // HTML documents have case-insensitive attribute matching
+    // (so we need to lowercase), non-HTML documents have
+    // case-sensitive attribute matching (so we should _not_ lowercase).
+    // However, HTML elements already have lowercased their attributes
+    // during parsing, so we do not need to do it again.
+    const bool lower_attrs_in_default_ns =
+        !element.IsHTMLElement() && IsA<HTMLDocument>(element.GetDocument());
+
+    // Due to lazy attributes, this can be a bit tricky. First of all,
+    // we need to make sure that if there's a dirty style attribute
+    // and there's a ruleset bucket for [style] selectors (which is extremely
+    // unusual, but allowed), we check the rules in that bucket.
+    // We do this by means of synchronizing the style attribute before
+    // iterating, but only if there's actually such a bucket, as it's fairly
+    // expensive to do so. (We have a similar issue with SVG attributes,
+    // but it is tricky enough to identify if there are any such buckets
+    // that we simply always synchronize them if there are any attribute
+    // ruleset buckets at all. We can always revisit this if there are any
+    // slowdowns from SVG attribute synchronization.)
+    //
+    // Second, CollectMatchingRulesForList() may call member functions
+    // that synchronize the element, adding new attributes to the list
+    // while we iterate. These are not relevant for correctness (we
+    // would never find any rule buckets matching them anyway),
+    // but they may cause reallocation of the vector. For this reason,
+    // we cannot use range-based iterators over the attributes here
+    // if we don't synchronize before the loop; we need to use
+    // simple indexes and then refresh the span after every call.
+    bool need_style_synchronized =
+        match_request.rule_set->HasBucketForStyleAttribute();
+    base::span<const Attribute> attributes =
+        GetAttributes(element, need_style_synchronized);
+
+    for (unsigned attr_idx = 0; attr_idx < attributes.size(); ++attr_idx) {
+      const AtomicString& attribute_name = attributes[attr_idx].LocalName();
+      // NOTE: Attributes in non-default namespaces are case-sensitive.
+      // There is a bug where you can set mixed-cased attributes (in non-default
+      // namespaces) with setAttributeNS(), but they never match anything.
+      // (The relevant code is in AnyAttributeMatches(), in
+      // selector_checker.cc.) What we're doing here doesn't influence that bug.
+      const AtomicString& lower_name =
+          (lower_attrs_in_default_ns &&
+           attributes[attr_idx].NamespaceURI() == g_null_atom)
+              ? attribute_name.LowerASCII()
+              : attribute_name;
+      CollectMatchingRulesForList(match_request.rule_set->AttrRules(lower_name),
+                                  match_request, checker);
+
+      const AttributeCollection collection = element.AttributesWithoutUpdate();
+      attributes = {collection.data(), collection.size()};
+    }
+  }
+
   if (element.IsLink()) {
     CollectMatchingRulesForList(match_request.rule_set->LinkPseudoClassRules(),
                                 match_request, checker);
diff --git a/third_party/blink/renderer/core/css/rule_set.cc b/third_party/blink/renderer/core/css/rule_set.cc
index 1ea237c8..5f1f41c 100644
--- a/third_party/blink/renderer/core/css/rule_set.cc
+++ b/third_party/blink/renderer/core/css/rule_set.cc
@@ -146,6 +146,7 @@
 static void ExtractSelectorValues(const CSSSelector* selector,
                                   AtomicString& id,
                                   AtomicString& class_name,
+                                  AtomicString& attr_name,
                                   AtomicString& custom_pseudo_element_name,
                                   AtomicString& tag_name,
                                   AtomicString& part_name,
@@ -193,6 +194,15 @@
           break;
       }
       break;
+    case CSSSelector::kAttributeExact:
+    case CSSSelector::kAttributeSet:
+    case CSSSelector::kAttributeHyphen:
+    case CSSSelector::kAttributeList:
+    case CSSSelector::kAttributeContain:
+    case CSSSelector::kAttributeBegin:
+    case CSSSelector::kAttributeEnd:
+      attr_name = selector->Attribute().LocalName();
+      break;
     default:
       break;
   }
@@ -202,6 +212,7 @@
                                     RuleData* rule_data) {
   AtomicString id;
   AtomicString class_name;
+  AtomicString attr_name;
   AtomicString custom_pseudo_element_name;
   AtomicString tag_name;
   AtomicString part_name;
@@ -214,12 +225,14 @@
   const CSSSelector* it = &component;
   for (; it && it->Relation() == CSSSelector::kSubSelector;
        it = it->TagHistory()) {
-    ExtractSelectorValues(it, id, class_name, custom_pseudo_element_name,
-                          tag_name, part_name, pseudo_type);
+    ExtractSelectorValues(it, id, class_name, attr_name,
+                          custom_pseudo_element_name, tag_name, part_name,
+                          pseudo_type);
   }
   if (it) {
-    ExtractSelectorValues(it, id, class_name, custom_pseudo_element_name,
-                          tag_name, part_name, pseudo_type);
+    ExtractSelectorValues(it, id, class_name, attr_name,
+                          custom_pseudo_element_name, tag_name, part_name,
+                          pseudo_type);
   }
 
   // Prefer rule sets in order of most likely to apply infrequently.
@@ -233,6 +246,14 @@
     return true;
   }
 
+  if (!attr_name.IsEmpty()) {
+    AddToRuleSet(attr_name, EnsurePendingRules()->attr_rules, rule_data);
+    if (attr_name == html_names::kStyleAttr) {
+      has_bucket_for_style_attr_ = true;
+    }
+    return true;
+  }
+
   if (!custom_pseudo_element_name.IsEmpty()) {
     // Custom pseudos come before ids and classes in the order of tagHistory,
     // and have a relation of ShadowPseudo between them. Therefore we should
@@ -550,6 +571,7 @@
   PendingRuleMaps* pending_rules = pending_rules_.Release();
   CompactPendingRules(pending_rules->id_rules, id_rules_);
   CompactPendingRules(pending_rules->class_rules, class_rules_);
+  CompactPendingRules(pending_rules->attr_rules, attr_rules_);
   CompactPendingRules(pending_rules->tag_rules, tag_rules_);
   CompactPendingRules(pending_rules->ua_shadow_pseudo_element_rules,
                       ua_shadow_pseudo_element_rules_);
@@ -672,6 +694,7 @@
 void RuleSet::PendingRuleMaps::Trace(Visitor* visitor) const {
   visitor->Trace(id_rules);
   visitor->Trace(class_rules);
+  visitor->Trace(attr_rules);
   visitor->Trace(tag_rules);
   visitor->Trace(ua_shadow_pseudo_element_rules);
 }
@@ -683,6 +706,7 @@
 void RuleSet::Trace(Visitor* visitor) const {
   visitor->Trace(id_rules_);
   visitor->Trace(class_rules_);
+  visitor->Trace(attr_rules_);
   visitor->Trace(tag_rules_);
   visitor->Trace(ua_shadow_pseudo_element_rules_);
   visitor->Trace(link_pseudo_class_rules_);
diff --git a/third_party/blink/renderer/core/css/rule_set.h b/third_party/blink/renderer/core/css/rule_set.h
index 1a57ef5..1c622d7 100644
--- a/third_party/blink/renderer/core/css/rule_set.h
+++ b/third_party/blink/renderer/core/css/rule_set.h
@@ -219,7 +219,7 @@
 // ElementRuleCollector::CollectMatchingRules.
 class CORE_EXPORT RuleSet final : public GarbageCollected<RuleSet> {
  public:
-  RuleSet() : rule_count_(0) {}
+  RuleSet() = default;
   RuleSet(const RuleSet&) = delete;
   RuleSet& operator=(const RuleSet&) = delete;
 
@@ -243,6 +243,13 @@
     auto it = class_rules_.find(key);
     return it != class_rules_.end() ? it->value : nullptr;
   }
+  bool HasAnyAttrRules() const { return !attr_rules_.IsEmpty(); }
+  const HeapVector<Member<const RuleData>>* AttrRules(
+      const AtomicString& key) const {
+    DCHECK(!pending_rules_);
+    auto it = attr_rules_.find(key);
+    return it != attr_rules_.end() ? it->value : nullptr;
+  }
   const HeapVector<Member<const RuleData>>* TagRules(
       const AtomicString& key) const {
     DCHECK(!pending_rules_);
@@ -336,6 +343,8 @@
     return !slotted_pseudo_element_rules_.IsEmpty();
   }
 
+  bool HasBucketForStyleAttribute() const { return has_bucket_for_style_attr_; }
+
   bool NeedsFullRecalcForRuleSetInvalidation() const {
     return features_.NeedsFullRecalcForRuleSetInvalidation();
   }
@@ -411,6 +420,7 @@
 
     PendingRuleMap id_rules;
     PendingRuleMap class_rules;
+    PendingRuleMap attr_rules;
     PendingRuleMap tag_rules;
     PendingRuleMap ua_shadow_pseudo_element_rules;
 
@@ -442,6 +452,7 @@
 
   CompactRuleMap id_rules_;
   CompactRuleMap class_rules_;
+  CompactRuleMap attr_rules_;
   CompactRuleMap tag_rules_;
   CompactRuleMap ua_shadow_pseudo_element_rules_;
   HeapVector<Member<const RuleData>> link_pseudo_class_rules_;
@@ -463,7 +474,13 @@
   HeapVector<Member<StyleRuleScrollTimeline>> scroll_timeline_rules_;
   Vector<MediaQuerySetResult> media_query_set_results_;
 
-  unsigned rule_count_;
+  // Whether there is a ruleset bucket for rules with a selector on
+  // the style attribute (which is rare, but allowed). If so, the caller
+  // may need to take extra steps to synchronize the style attribute on
+  // an element before looking for appropriate buckets.
+  bool has_bucket_for_style_attr_ = false;
+
+  unsigned rule_count_ = 0;
   Member<PendingRuleMaps> pending_rules_;
 
   // nullptr if the stylesheet doesn't explicitly declare any layer.
diff --git a/third_party/blink/renderer/core/css/rule_set_test.cc b/third_party/blink/renderer/core/css/rule_set_test.cc
index 9cf40aa..eaa4202 100644
--- a/third_party/blink/renderer/core/css/rule_set_test.cc
+++ b/third_party/blink/renderer/core/css/rule_set_test.cc
@@ -139,6 +139,24 @@
   ASSERT_EQ(tag_str, rules->at(0)->Selector().TagQName().LocalName());
 }
 
+TEST(RuleSetTest, findBestRuleSetAndAdd_TagThenAttr) {
+  css_test_helpers::TestStyleSheet sheet;
+
+  sheet.AddCSSRules("div[attr] { }");
+  RuleSet& rule_set = sheet.GetRuleSet();
+  ASSERT_EQ(1u, rule_set.AttrRules("attr")->size());
+  ASSERT_FALSE(rule_set.TagRules("div"));
+}
+
+TEST(RuleSetTest, findBestRuleSetAndAdd_AttrThenClass) {
+  css_test_helpers::TestStyleSheet sheet;
+
+  sheet.AddCSSRules("[attr].class { }");
+  RuleSet& rule_set = sheet.GetRuleSet();
+  ASSERT_FALSE(rule_set.AttrRules("attr"));
+  ASSERT_EQ(1u, rule_set.ClassRules("class")->size());
+}
+
 TEST(RuleSetTest, findBestRuleSetAndAdd_Host) {
   css_test_helpers::TestStyleSheet sheet;
 
@@ -214,9 +232,8 @@
   sheet.AddCSSRules(":focus { }");
   sheet.AddCSSRules("[attr]:focus { }");
   RuleSet& rule_set = sheet.GetRuleSet();
-  const HeapVector<Member<const RuleData>>* rules =
-      rule_set.FocusPseudoClassRules();
-  ASSERT_EQ(2u, rules->size());
+  ASSERT_EQ(1u, rule_set.FocusPseudoClassRules()->size());
+  ASSERT_EQ(1u, rule_set.AttrRules("attr")->size());
 }
 
 TEST(RuleSetTest, findBestRuleSetAndAdd_LinkVisited) {
@@ -229,9 +246,8 @@
   sheet.AddCSSRules(":-webkit-any-link { }");
   sheet.AddCSSRules("[attr]:-webkit-any-link { }");
   RuleSet& rule_set = sheet.GetRuleSet();
-  const HeapVector<Member<const RuleData>>* rules =
-      rule_set.LinkPseudoClassRules();
-  ASSERT_EQ(6u, rules->size());
+  ASSERT_EQ(3u, rule_set.LinkPseudoClassRules()->size());
+  ASSERT_EQ(3u, rule_set.AttrRules("attr")->size());
 }
 
 TEST(RuleSetTest, findBestRuleSetAndAdd_Cue) {
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc
index 6687068..394c894 100644
--- a/third_party/blink/renderer/core/css/selector_checker.cc
+++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -541,6 +541,9 @@
       // are lower-cased for selectors in html documents. Compare the selector
       // and the attribute local name insensitively to e.g. allow matching SVG
       // attributes like viewBox.
+      //
+      // NOTE: If changing this behavior, be sure to also update the bucketing
+      // in ElementRuleCollector::CollectMatchingRules() accordingly.
       if (!attribute_item.MatchesCaseInsensitive(selector_attr))
         continue;
     }
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.cc b/third_party/blink/renderer/core/css/style_property_serializer.cc
index 501ff64..856cf75f 100644
--- a/third_party/blink/renderer/core/css/style_property_serializer.cc
+++ b/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -1263,7 +1263,8 @@
 
   StringBuilder auto_flow_text;
   auto_flow_text.Append("auto-flow ");
-  if (auto_flow_value_list->HasValue(
+  if (auto_flow_value_list &&
+      auto_flow_value_list->HasValue(
           *CSSIdentifierValue::Create(CSSValueID::kDense))) {
     auto_flow_text.Append("dense ");
   }
@@ -1271,7 +1272,8 @@
   // 2- <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>?
   // | [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>
   StringBuilder result;
-  if (auto_flow_value_list->HasValue(
+  if (auto_flow_value_list &&
+      auto_flow_value_list->HasValue(
           *CSSIdentifierValue::Create(CSSValueID::kColumn))) {
     result.Append(template_row_values->CssText());
     result.Append(" / ");
diff --git a/third_party/blink/renderer/core/dom/attribute_collection.h b/third_party/blink/renderer/core/dom/attribute_collection.h
index c403f85..b941a87 100644
--- a/third_party/blink/renderer/core/dom/attribute_collection.h
+++ b/third_party/blink/renderer/core/dom/attribute_collection.h
@@ -56,6 +56,9 @@
     return begin()[index];
   }
 
+  ValueType* data() { return attributes_.data(); }
+  const ValueType* data() const { return attributes_.data(); }
+
   iterator begin() const { return attributes_.data(); }
   iterator end() const { return begin() + size(); }
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 770712b..3cd2bbe 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1083,6 +1083,12 @@
     DCHECK(IsStyledElement());
     SynchronizeStyleAttributeInternal();
   }
+  SynchronizeAllAttributesExceptStyle();
+}
+
+void Element::SynchronizeAllAttributesExceptStyle() const {
+  if (!GetElementData())
+    return;
   if (GetElementData()->svg_attributes_are_dirty())
     To<SVGElement>(this)->SynchronizeSVGAttribute(AnyQName());
 }
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 36d96ac..392b5d9 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -319,6 +319,11 @@
   // This variant will not update the potentially invalid attributes. To be used
   // when not interested in style attribute or one of the SVG attributes.
   AttributeCollection AttributesWithoutUpdate() const;
+  // Similar to AttributesWithoutUpdate(), but with only the style attribute
+  // exempt (ie., SVG attributes are always synchronized, for simplicity).
+  // The style attribute is special because it is so frequently updated from
+  // JavaScript and also easily identifiable (it is a single attribute).
+  AttributeCollection AttributesWithoutStyleUpdate() const;
 
   void scrollIntoView(const V8UnionBooleanOrScrollIntoViewOptions* arg);
   void scrollIntoView(bool align_to_top = true);
@@ -1281,6 +1286,7 @@
 
   void SynchronizeAllAttributes() const;
   void SynchronizeAttribute(const QualifiedName&) const;
+  void SynchronizeAllAttributesExceptStyle() const;
 
   void UpdateId(const AtomicString& old_id, const AtomicString& new_id);
   void UpdateId(TreeScope&,
@@ -1462,7 +1468,6 @@
   static bool AllowFrom(const Node& node) { return node.IsElementNode(); }
 };
 
-
 inline bool IsDisabledFormControl(const Node* node) {
   auto* element = DynamicTo<Element>(node);
   return element && element->IsDisabledFormControl();
@@ -1507,6 +1512,13 @@
   return GetElementData()->Attributes();
 }
 
+inline AttributeCollection Element::AttributesWithoutStyleUpdate() const {
+  if (!GetElementData())
+    return AttributeCollection();
+  SynchronizeAllAttributesExceptStyle();
+  return GetElementData()->Attributes();
+}
+
 inline bool Element::hasAttributes() const {
   return !Attributes().IsEmpty();
 }
diff --git a/third_party/blink/renderer/core/fragment_directive/css_selector_fragment_anchor_test.cc b/third_party/blink/renderer/core/fragment_directive/css_selector_fragment_anchor_test.cc
index cd0f9d1..d0fc3283 100644
--- a/third_party/blink/renderer/core/fragment_directive/css_selector_fragment_anchor_test.cc
+++ b/third_party/blink/renderer/core/fragment_directive/css_selector_fragment_anchor_test.cc
@@ -308,11 +308,12 @@
   EXPECT_EQ(GetDocument().Url(), "https://example.com/test.html");
 }
 
-// Make sure fragment is dismissed after user clicks
-TEST_F(CssSelectorFragmentAnchorTest, DismissFragmentAfterUserClicks) {
+// Make sure fragment is not dismissed after user clicks
+TEST_F(CssSelectorFragmentAnchorTest, FragmentStaysAfterUserClicks) {
   base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndEnableFeature(
-      blink::features::kCssSelectorFragmentAnchor);
+  feature_list_.InitWithFeatures(
+      /*enabled_features=*/{blink::features::kCssSelectorFragmentAnchor},
+      /*disabled_features=*/{});
 
   SimRequest main_request(
       "https://example.com/"
@@ -343,6 +344,13 @@
   test::RunPendingTasks();
   Compositor().BeginFrame();
 
+  KURL expected_url = GetDocument()
+                          .GetFrame()
+                          ->Loader()
+                          .GetDocumentLoader()
+                          ->GetHistoryItem()
+                          ->Url();
+
   Element& img = *GetDocument().getElementById("image");
   EXPECT_TRUE(IsVisibleInViewport(img))
       << "<img> Element wasn't scrolled into view, viewport's scroll offset: "
@@ -351,7 +359,7 @@
 
   SimulateClick(100, 100);
 
-  EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
 
   KURL url = GetDocument()
                  .GetFrame()
@@ -359,7 +367,8 @@
                  .GetDocumentLoader()
                  ->GetHistoryItem()
                  ->Url();
-  EXPECT_EQ("https://example.com/test.html", url);
+
+  EXPECT_EQ(expected_url, url);
 }
 
 // Although parsed correctly, the element is not found, hence no scroll happens
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor.cc b/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor.cc
index 74116e6..ac91c506 100644
--- a/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor.cc
+++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor.cc
@@ -45,6 +45,9 @@
   if (!frame.Loader().GetDocumentLoader()->ConsumeTextFragmentToken())
     return false;
 
+  if (frame.GetDocument()->contentType() != "text/html")
+    return false;
+
   // For cross origin initiated navigations, we only allow text
   // fragments if the frame is not script accessible by another frame, i.e. no
   // cross origin iframes or window.open.
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_metrics.cc b/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_metrics.cc
index 62c5a232..2a8b8ce 100644
--- a/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_metrics.cc
+++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_metrics.cc
@@ -213,7 +213,6 @@
 void TextFragmentAnchorMetrics::Dismissed() {
   // We report Dismissed separately from ReportMetrics as it may or may not
   // get called in the lifetime of the TextFragmentAnchor.
-  UseCounter::Count(document_, WebFeature::kTextFragmentAnchorTapToDismiss);
   TRACE_EVENT_INSTANT0("blink", "TextFragmentAnchorMetrics::Dismissed",
                        TRACE_EVENT_SCOPE_THREAD);
 }
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_metrics_test.cc b/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_metrics_test.cc
index 8371689b..03951d3 100644
--- a/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_metrics_test.cc
+++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_metrics_test.cc
@@ -1049,43 +1049,6 @@
   }
 }
 
-// Test that the TapToDismiss feature gets use counted when the user taps to
-// dismiss the text highlight
-TEST_F(TextFragmentAnchorMetricsTest, TapToDismiss) {
-  SimRequest request("https://example.com/test.html#:~:text=test%20page",
-                     "text/html");
-  LoadURL("https://example.com/test.html#:~:text=test%20page");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      body {
-        height: 2200px;
-      }
-      p {
-        position: absolute;
-        top: 1000px;
-      }
-    </style>
-    <p>This is a test page</p>
-  )HTML");
-  RunAsyncMatchingTasks();
-
-  // Render two frames to handle the async step added by the beforematch event.
-  Compositor().BeginFrame();
-  BeginEmptyFrame();
-
-  EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kTextFragmentAnchor));
-  EXPECT_TRUE(
-      GetDocument().IsUseCounted(WebFeature::kTextFragmentAnchorMatchFound));
-  EXPECT_FALSE(
-      GetDocument().IsUseCounted(WebFeature::kTextFragmentAnchorTapToDismiss));
-
-  SimulateClick(100, 100);
-
-  EXPECT_TRUE(
-      GetDocument().IsUseCounted(WebFeature::kTextFragmentAnchorTapToDismiss));
-}
-
 // Test counting cases where the fragment directive fails to parse.
 TEST_F(TextFragmentAnchorMetricsTest, InvalidFragmentDirective) {
   const int kUncounted = 0;
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_test.cc b/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_test.cc
index ef79fdf..9be3878 100644
--- a/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_test.cc
+++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_anchor_test.cc
@@ -1046,11 +1046,8 @@
   EXPECT_EQ(14u, markers.at(0)->EndOffset());
 }
 
-// Test that user scrolling dismisses the highlight.
-TEST_P(TextFragmentAnchorScrollTest, DismissTextHighlightOnUserScroll) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndDisableFeature(
-      shared_highlighting::kSharedHighlightingV2);
+// Test that user scrolling keeps the highlight.
+TEST_P(TextFragmentAnchorScrollTest, KeepTextHighlightOnUserScroll) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1089,21 +1086,13 @@
 
   Compositor().BeginFrame();
 
-  if (IsUserScrollType()) {
-    EXPECT_EQ(0u, GetDocument().Markers().Markers().size());
-    EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
-  } else {
-    EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
-    EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
-  }
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
 }
 
 // Test that user scrolling doesn't dismiss the highlight, when the
 // SharedHighlightingV2 flag is enabled.
 TEST_P(TextFragmentAnchorScrollTest, DontDismissTextHighlightOnUserScroll) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndEnableFeature(
-      shared_highlighting::kSharedHighlightingV2);
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1594,11 +1583,8 @@
   EXPECT_EQ(17u, markers.at(0)->EndOffset());
 }
 
-// Test dismissing the text highlight with a click
+// Test click keeps the text highlight
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightWithClick) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndDisableFeature(
-      shared_highlighting::kSharedHighlightingV2);
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1643,25 +1629,23 @@
 
   SimulateClick(100, 100);
 
-  EXPECT_EQ(0u, GetDocument().Markers().Markers().size());
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
 
-  // Ensure the fragment is uninstalled
-  EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
   url = GetDocument()
             .GetFrame()
             ->Loader()
             .GetDocumentLoader()
             ->GetHistoryItem()
             ->Url();
-  EXPECT_EQ("https://example.com/test.html", url.GetString());
+  EXPECT_EQ(
+      "https://example.com/test.html#:~:text=test%20page&text=more%20text",
+      url.GetString());
 }
 
 // Test not dismissing the text highlight with a click, if the
 // SharedHighlightingV2 flag is enabled.
 TEST_F(TextFragmentAnchorTest, DontDismissTextHighlightWithClick) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndEnableFeature(
-      shared_highlighting::kSharedHighlightingV2);
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1703,11 +1687,8 @@
   EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
 }
 
-// Test dismissing the text highlight with a tap
-TEST_F(TextFragmentAnchorTest, DismissTextHighlightWithTap) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndDisableFeature(
-      shared_highlighting::kSharedHighlightingV2);
+// Test that a tap keeps the text highlight
+TEST_F(TextFragmentAnchorTest, KeepsTextHighlightWithTap) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1752,25 +1733,23 @@
 
   SimulateTap(100, 100);
 
-  EXPECT_EQ(0u, GetDocument().Markers().Markers().size());
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
 
-  // Ensure the fragment is uninstalled
-  EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
   url = GetDocument()
             .GetFrame()
             ->Loader()
             .GetDocumentLoader()
             ->GetHistoryItem()
             ->Url();
-  EXPECT_EQ("https://example.com/test.html", url.GetString());
+  EXPECT_EQ(
+      "https://example.com/test.html#:~:text=test%20page&text=more%20text",
+      url.GetString());
 }
 
 // Test not dismissing the text highlight with a tap, if the
 // SharedHighlightingV2 flag is enabled.
 TEST_F(TextFragmentAnchorTest, DontDismissTextHighlightWithTap) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndEnableFeature(
-      shared_highlighting::kSharedHighlightingV2);
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1812,11 +1791,9 @@
   EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
 }
 
-// Test that we don't dismiss a text highlight before it's scrolled into view
-TEST_F(TextFragmentAnchorTest, DismissTextHighlightOutOfView) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndDisableFeature(
-      shared_highlighting::kSharedHighlightingV2);
+// Test that we don't dismiss a text highlight before and after it's scrolled
+// into view
+TEST_F(TextFragmentAnchorTest, KeepsTextHighlightOutOfView) {
   SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
   SimSubresourceRequest css_request("https://example.com/test.css", "text/css");
   LoadURL("https://example.com/test.html#:~:text=test");
@@ -1850,17 +1827,15 @@
 
   EXPECT_EQ(1u, GetDocument().Markers().Markers().size());
 
-  // Click to dismiss
+  // Click
   SimulateClick(100, 100);
-  EXPECT_EQ(0u, GetDocument().Markers().Markers().size());
-  EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
+  EXPECT_EQ(1u, GetDocument().Markers().Markers().size());
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
 }
 
-// Test dismissing a text highlight that didn't require a scroll into view
-TEST_F(TextFragmentAnchorTest, DismissTextHighlightInView) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndDisableFeature(
-      shared_highlighting::kSharedHighlightingV2);
+// Test that a text highlight that didn't require a scroll into view is kept on
+// tap
+TEST_F(TextFragmentAnchorTest, KeepsTextHighlightInView) {
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1890,10 +1865,8 @@
 
   SimulateTap(100, 100);
 
-  EXPECT_EQ(0u, GetDocument().Markers().Markers().size());
-
-  // Ensure the fragment is uninstalled
-  EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
+  EXPECT_EQ(1u, GetDocument().Markers().Markers().size());
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
 }
 
 // Test that the fragment directive delimiter :~: works properly and is stripped
@@ -2376,9 +2349,6 @@
 }
 
 TEST_F(TextFragmentAnchorTest, OpenedFromHighlightDoesNotSelectAdditionalText) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndEnableFeature(
-      shared_highlighting::kSharedHighlightingV2);
   SimRequest request("https://www.test.com/#:~:text=First%20test,page%20three",
                      "text/html");
   LoadURL("https://www.test.com/#:~:text=First%20test,page%20three");
@@ -2457,9 +2427,6 @@
 // a text fragment, when the TextFragmentTapOpensContextMenu
 // RuntimeEnabledFeature is enabled.
 TEST_F(TextFragmentAnchorTest, ShouldOpenContextMenuOnTap) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndEnableFeature(
-      shared_highlighting::kSharedHighlightingV2);
   LoadAhem();
   SimRequest request(
       "https://example.com/"
@@ -2559,9 +2526,6 @@
 // selected. RuntimeEnabledFeature is enabled.
 TEST_F(TextFragmentAnchorTest,
        ShouldNotRequestUnhandledTapNotifierWhenTapOnTextFragment) {
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndEnableFeature(
-      shared_highlighting::kSharedHighlightingV2);
   LoadAhem();
   SimRequest request(
       "https://example.com/"
@@ -2623,9 +2587,6 @@
 
 TEST_F(TextFragmentAnchorTest, TapOpeningContextMenuWithDirtyLifecycleNoCrash) {
   ScopedTextFragmentTapOpensContextMenuForTest tap_opens_context_menu(true);
-  base::test::ScopedFeatureList feature_list_;
-  feature_list_.InitAndEnableFeature(
-      shared_highlighting::kSharedHighlightingV2);
 
   SimRequest request(
       "https://example.com/"
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc
index e39d2fda..18974f9 100644
--- a/third_party/blink/renderer/core/frame/dom_window.cc
+++ b/third_party/blink/renderer/core/frame/dom_window.cc
@@ -680,7 +680,7 @@
       options->hasDelegate()) {
     Vector<String> capability_list;
     options->delegate().Split(' ', capability_list);
-    delegate_payment_request = capability_list.Contains("paymentrequest");
+    delegate_payment_request = capability_list.Contains("payment");
   }
 
   PostedMessage* posted_message = MakeGarbageCollected<PostedMessage>();
diff --git a/third_party/blink/renderer/core/frame/dom_window.h b/third_party/blink/renderer/core/frame/dom_window.h
index 886f8708..2f9bb79 100644
--- a/third_party/blink/renderer/core/frame/dom_window.h
+++ b/third_party/blink/renderer/core/frame/dom_window.h
@@ -152,6 +152,8 @@
   // marked as "CrossOrigin" in the window.idl.
   void ReportCoopAccess(const char* property_name);
 
+  bool anonymous() const { return anonymous_; }
+
  protected:
   explicit DOMWindow(Frame&);
 
@@ -210,6 +212,10 @@
     WTF::String reported_window_url;
   };
   WTF::Vector<CoopAccessMonitor> coop_access_monitor_;
+
+  // Anonymous Iframe:
+  // https://github.com/camillelamy/explainers/blob/main/anonymous_iframes.md
+  const bool anonymous_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 02bec9e..2db68df 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -201,7 +201,9 @@
       online_observer_handle_;
 };
 
-LocalDOMWindow::LocalDOMWindow(LocalFrame& frame, WindowAgent* agent)
+LocalDOMWindow::LocalDOMWindow(LocalFrame& frame,
+                               WindowAgent* agent,
+                               bool anonymous)
     : DOMWindow(frame),
       ExecutionContext(V8PerIsolateData::MainThreadIsolate(), agent),
       script_controller_(MakeGarbageCollected<ScriptController>(
@@ -219,8 +221,8 @@
           MakeGarbageCollected<
               HeapHashMap<int, Member<ContentSecurityPolicy>>>()),
       token_(frame.GetLocalFrameToken()),
-      network_state_observer_(
-          MakeGarbageCollected<NetworkStateObserver>(this)) {}
+      network_state_observer_(MakeGarbageCollected<NetworkStateObserver>(this)),
+      anonymous_(anonymous) {}
 
 void LocalDOMWindow::BindContentSecurityPolicy() {
   DCHECK(!GetContentSecurityPolicy()->IsBound());
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index 00149c91..5276a0b 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -118,7 +118,7 @@
 
   static LocalDOMWindow* From(const ScriptState*);
 
-  LocalDOMWindow(LocalFrame&, WindowAgent*);
+  LocalDOMWindow(LocalFrame&, WindowAgent*, bool anonymous);
   ~LocalDOMWindow() override;
 
   // Returns the token identifying the frame that this ExecutionContext was
@@ -460,6 +460,9 @@
   // destroyed in this ExecutionContext.
   void RemoveDedicatedWorker(DedicatedWorker* dedicated_worker);
 
+  // Whether the window is anonymous or not.
+  bool anonymous() const { return anonymous_; }
+
  protected:
   // EventTarget overrides.
   void AddedEventListener(const AtomicString& event_type,
@@ -584,6 +587,10 @@
 
   // The set of DedicatedWorkers that are created in this ExecutionContext.
   HeapHashSet<Member<DedicatedWorker>> dedicated_workers_;
+
+  // Anonymous Iframe:
+  // https://github.com/camillelamy/explainers/blob/main/anonymous_iframes.md
+  const bool anonymous_;
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 94a609a0..9517ed9 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -999,7 +999,7 @@
       "window.frames[0].postMessage('0', {targetOrigin: '*'});");
   String post_message_w_payment_request(
       "window.frames[0].postMessage("
-      "'1', {targetOrigin: '*', delegate: 'paymentrequest'});");
+      "'1', {targetOrigin: '*', delegate: 'payment'});");
 
   // The delegation info is not passed through a postMessage that is sent
   // without either user activation or the delegation option.
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl
index df8f51e..8f0bc263 100644
--- a/third_party/blink/renderer/core/frame/window.idl
+++ b/third_party/blink/renderer/core/frame/window.idl
@@ -206,6 +206,10 @@
 
     // TrustedTypes API: http://github.com/wicg/trusted-types
     [RuntimeEnabled=TrustedDOMTypes, CallWith=ScriptState] readonly attribute TrustedTypePolicyFactory trustedTypes;
+
+    // Anonymous iframe:
+    // https://github.com/camillelamy/explainers/blob/main/anonymous_iframes.md
+    [RuntimeEnabled=AnonymousIframe] readonly attribute boolean anonymous;
 };
 
 Window includes GlobalEventHandlers;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
index 15073bda..08b803e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
@@ -276,11 +276,11 @@
         << unit.TextContentEnd() << "<=" << text.length();
     unit.AssertValid();
   }
-  for (const auto& pair : ranges) {
+  for (const auto& pair : ranges_) {
     SECURITY_DCHECK(pair.value.first < units_.size())
         << pair.value.first << "<" << units_.size();
-    SECURITY_DCHECK(pair.value.second < units_.size())
-        << pair.value.second << "<" << units_.size();
+    SECURITY_DCHECK(pair.value.second <= units_.size())
+        << pair.value.second << "<=" << units_.size();
   }
 #endif
 }
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index e3fab42..6863435 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -315,6 +315,7 @@
   std::unique_ptr<CodeCacheHost> code_cache_host;
   HashSet<KURL> early_hints_preloaded_resources;
   absl::optional<Vector<KURL>> ad_auction_components;
+  bool anonymous;
 };
 
 // Asserts size of DocumentLoader, so that whenever a new attribute is added to
@@ -412,7 +413,8 @@
       is_cross_site_cross_browsing_context_group_(
           params_->is_cross_site_cross_browsing_context_group),
       app_history_back_entries_(params_->app_history_back_entries),
-      app_history_forward_entries_(params_->app_history_forward_entries) {
+      app_history_forward_entries_(params_->app_history_forward_entries),
+      anonymous_(params_->anonymous) {
   DCHECK(frame_);
 
   // See `archive_` attribute documentation.
@@ -539,6 +541,7 @@
       CopyInitiatorOriginTrials(initiator_origin_trial_features_);
   params->force_enabled_origin_trials =
       CopyForceEnabledOriginTrials(force_enabled_origin_trials_);
+  params->anonymous = anonymous_;
   for (const auto& resource : early_hints_preloaded_resources_)
     params->early_hints_preloaded_resources.push_back(resource);
   if (ad_auction_components_) {
@@ -1970,11 +1973,24 @@
 }
 
 bool ShouldReuseDOMWindow(LocalDOMWindow* window,
-                          SecurityOrigin* security_origin) {
-  // Secure transitions can only happen when navigating from the initial empty
-  // document.
-  return window && window->document()->IsInitialEmptyDocument() &&
-         window->GetSecurityOrigin()->CanAccess(security_origin);
+                          SecurityOrigin* security_origin,
+                          bool anonymous) {
+  if (!window) {
+    return false;
+  }
+
+  // Anonymous is tracked per-Window, so if it does not match, do not reuse it.
+  if (anonymous != window->anonymous()) {
+    return false;
+  }
+
+  // Only navigations from the initial empty document can reuse the window.
+  if (!window->document()->IsInitialEmptyDocument()) {
+    return false;
+  }
+
+  // The new origin must match the origin of the initial empty document.
+  return window->GetSecurityOrigin()->CanAccess(security_origin);
 }
 
 namespace {
@@ -2084,10 +2100,12 @@
   // commits. To make that happen, we "securely transition" the existing
   // LocalDOMWindow to the Document that results from the network load. See also
   // Document::IsSecureTransitionTo.
-  if (!ShouldReuseDOMWindow(frame_->DomWindow(), security_origin.get())) {
+  if (!ShouldReuseDOMWindow(frame_->DomWindow(), security_origin.get(),
+                            anonymous_)) {
     auto* agent = GetWindowAgentForOrigin(frame_.Get(), security_origin.get(),
                                           origin_agent_cluster);
-    frame_->SetDOMWindow(MakeGarbageCollected<LocalDOMWindow>(*frame_, agent));
+    frame_->SetDOMWindow(
+        MakeGarbageCollected<LocalDOMWindow>(*frame_, agent, anonymous_));
 
     if (origin_policy_.has_value()) {
       // Convert from WebVector<WebString> to WTF::Vector<WTF::String>
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index 6b630b1..a89de04 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -653,6 +653,9 @@
   // contains URNs to the ad components returned by the winning bid. Null,
   // otherwise.
   absl::optional<Vector<KURL>> ad_auction_components_;
+
+  // Whether the document should be anonymous or not.
+  const bool anonymous_ = false;
 };
 
 DECLARE_WEAK_IDENTIFIER_MAP(DocumentLoader);
diff --git a/third_party/blink/renderer/core/style/basic_shapes.cc b/third_party/blink/renderer/core/style/basic_shapes.cc
index 6c9a3d9..43ea0b3f 100644
--- a/third_party/blink/renderer/core/style/basic_shapes.cc
+++ b/third_party/blink/renderer/core/style/basic_shapes.cc
@@ -72,7 +72,7 @@
   gfx::PointF center =
       PointForCenterCoordinate(center_x_, center_y_, bounding_box.size());
   float radius = FloatValueForRadiusInBox(bounding_box.size());
-  path.AddEllipse(center, radius, radius);
+  path.AddEllipse(center + bounding_box.OffsetFromOrigin(), radius, radius);
 }
 
 bool BasicShapeEllipse::operator==(const BasicShape& o) const {
@@ -108,7 +108,7 @@
       FloatValueForRadiusInBox(radius_x_, center.x(), bounding_box.width());
   float radius_y =
       FloatValueForRadiusInBox(radius_y_, center.y(), bounding_box.height());
-  path.AddEllipse(center, radius_x, radius_y);
+  path.AddEllipse(center + bounding_box.OffsetFromOrigin(), radius_x, radius_y);
 }
 
 void BasicShapePolygon::GetPath(Path& path,
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc
index 3343448a..61b39f48 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc
@@ -259,19 +259,6 @@
   mojo_ptr_->RequestPermission(writable, std::move(callback));
 }
 
-void FileSystemDirectoryHandle::RenameImpl(
-    const String& new_entry_name,
-    base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr)> callback) {
-  if (!mojo_ptr_.is_bound()) {
-    std::move(callback).Run(mojom::blink::FileSystemAccessError::New(
-        mojom::blink::FileSystemAccessStatus::kInvalidState,
-        base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"));
-    return;
-  }
-
-  mojo_ptr_->Rename(new_entry_name, std::move(callback));
-}
-
 void FileSystemDirectoryHandle::MoveImpl(
     mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> dest,
     const String& new_entry_name,
@@ -283,7 +270,11 @@
     return;
   }
 
-  mojo_ptr_->Move(std::move(dest), new_entry_name, std::move(callback));
+  if (dest.is_valid()) {
+    mojo_ptr_->Move(std::move(dest), new_entry_name, std::move(callback));
+  } else {
+    mojo_ptr_->Rename(new_entry_name, std::move(callback));
+  }
 }
 
 void FileSystemDirectoryHandle::RemoveImpl(
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h
index 25830ab..6a6c011 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h
@@ -62,10 +62,6 @@
       bool writable,
       base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
                               mojom::blink::PermissionStatus)>) override;
-  void RenameImpl(
-      const String& new_entry_name,
-      base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr)>)
-      override;
   void MoveImpl(
       mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> dest,
       const String& new_entry_name,
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
index 1342555..a5c43881 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
@@ -201,19 +201,6 @@
   mojo_ptr_->RequestPermission(writable, std::move(callback));
 }
 
-void FileSystemFileHandle::RenameImpl(
-    const String& new_entry_name,
-    base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr)> callback) {
-  if (!mojo_ptr_.is_bound()) {
-    std::move(callback).Run(mojom::blink::FileSystemAccessError::New(
-        mojom::blink::FileSystemAccessStatus::kInvalidState,
-        base::File::Error::FILE_ERROR_FAILED, "Context Destroyed"));
-    return;
-  }
-
-  mojo_ptr_->Rename(new_entry_name, std::move(callback));
-}
-
 void FileSystemFileHandle::MoveImpl(
     mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> dest,
     const String& new_entry_name,
@@ -225,7 +212,11 @@
     return;
   }
 
-  mojo_ptr_->Move(std::move(dest), new_entry_name, std::move(callback));
+  if (dest.is_valid()) {
+    mojo_ptr_->Move(std::move(dest), new_entry_name, std::move(callback));
+  } else {
+    mojo_ptr_->Rename(new_entry_name, std::move(callback));
+  }
 }
 
 void FileSystemFileHandle::RemoveImpl(
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
index 4c7c2bc..0654b270 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
@@ -50,10 +50,6 @@
       bool writable,
       base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
                               mojom::blink::PermissionStatus)>) override;
-  void RenameImpl(
-      const String& new_entry_name,
-      base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr)>)
-      override;
   void MoveImpl(
       mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> dest,
       const String& new_entry_name,
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl
index 1f4495d6..eba6655 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.idl
@@ -25,7 +25,7 @@
     [
         CallWith=ScriptState,
         RuntimeEnabled=FileSystemAccessAccessHandle
-    ]  Promise<void> rename(USVString new_entry_name);
+    ]  Promise<void> move(USVString new_entry_name);
     [
         CallWith=ScriptState,
         RuntimeEnabled=FileSystemAccessAccessHandle
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc
index 390d58d..f095770 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc
@@ -97,13 +97,13 @@
   return result;
 }
 
-ScriptPromise FileSystemHandle::rename(ScriptState* script_state,
-                                       const String& new_entry_name) {
+ScriptPromise FileSystemHandle::move(ScriptState* script_state,
+                                     const String& new_entry_name) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise result = resolver->Promise();
 
-  RenameImpl(
-      new_entry_name,
+  MoveImpl(
+      mojo::NullRemote(), new_entry_name,
       WTF::Bind(
           [](FileSystemHandle* handle, const String& new_name,
              ScriptPromiseResolver* resolver, FileSystemAccessErrorPtr result) {
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
index d4ab9d8..bd7dffd 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
@@ -42,7 +42,7 @@
   ScriptPromise requestPermission(ScriptState*,
                                   const FileSystemHandlePermissionDescriptor*);
 
-  ScriptPromise rename(ScriptState*, const String& new_entry_name);
+  ScriptPromise move(ScriptState*, const String& new_entry_name);
   ScriptPromise move(ScriptState*,
                      FileSystemDirectoryHandle* destination_directory);
   ScriptPromise move(ScriptState*,
@@ -67,9 +67,6 @@
       bool writable,
       base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
                               mojom::blink::PermissionStatus)>) = 0;
-  virtual void RenameImpl(
-      const String& new_entry_name,
-      base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr)>) = 0;
   virtual void MoveImpl(
       mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken> dest,
       const String& new_entry_name,
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl b/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
index f08defee..e53d6aa 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
@@ -30,7 +30,7 @@
     [
         CallWith=ScriptState,
         RuntimeEnabled=FileSystemAccessAPIExperimental
-    ]  Promise<void> rename(USVString new_entry_name);
+    ]  Promise<void> move(USVString new_entry_name);
     [
         CallWith=ScriptState,
         RuntimeEnabled=FileSystemAccessAPIExperimental
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
index 88335c6..eaf5eee8 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
@@ -108,8 +108,26 @@
 constexpr const char* kExternalDecoderName = "ExternalDecoder";
 
 // Number of RTCVideoDecoder instances right now that have started decoding.
-std::atomic_int* GetDecoderCounter() {
-  static std::atomic_int s_counter(0);
+class DecoderCounter {
+ public:
+  int Count() { return count_.load(); }
+
+  void IncrementCount() {
+    int c = ++count_;
+    DCHECK_GT(c, 0);
+  }
+
+  void DecrementCount() {
+    int c = --count_;
+    DCHECK_GE(c, 0);
+  }
+
+ private:
+  std::atomic_int count_{0};
+};
+
+DecoderCounter* GetDecoderCounter() {
+  static DecoderCounter s_counter;
   // Note that this will init only in the first call in the ctor, so it's still
   // single threaded.
   return &s_counter;
@@ -340,7 +358,7 @@
 
     if (contributes_to_decoder_count_) {
       contributes_to_decoder_count_ = false;  // paranoia
-      --(*GetDecoderCounter());
+      GetDecoderCounter()->DecrementCount();
     }
   }
 }
@@ -452,7 +470,7 @@
     // for sites to create unused rtc codecs.
     if (!contributes_to_decoder_count_ && !prefer_software_decoders_) {
       contributes_to_decoder_count_ = true;
-      ++(*GetDecoderCounter());
+      GetDecoderCounter()->IncrementCount();
     }
 
     // Note that it's okay to FallBackToSoftwareLocked without a software
@@ -467,7 +485,7 @@
     // whatever threshold it uses.
     if (has_software_fallback && contributes_to_decoder_count_ &&
         current_resolution_.GetArea() < kMinResolution.GetArea() &&
-        GetDecoderCounter()->load() > kMaxDecoderInstances) {
+        GetDecoderCounter()->Count() > kMaxDecoderInstances) {
       return FallBackToSoftwareLocked();
     }
 
@@ -1127,7 +1145,7 @@
   // end up with the same hw decoder anyway.
   if (contributes_to_decoder_count_) {
     contributes_to_decoder_count_ = false;
-    --(*GetDecoderCounter());
+    GetDecoderCounter()->DecrementCount();
   }
 
   // If there aren't chrome sw decoders for DecoderStream to use, then give up
diff --git a/third_party/blink/web_tests/FlagExpectations/highdpi b/third_party/blink/web_tests/FlagExpectations/highdpi
index e84955b..c23a28b 100644
--- a/third_party/blink/web_tests/FlagExpectations/highdpi
+++ b/third_party/blink/web_tests/FlagExpectations/highdpi
@@ -187,7 +187,7 @@
 fast/borders/border-image-outset.html [ Pass ]
 fast/box-shadow/box-shadow.html [ Pass ]
 fast/box-sizing/box-sizing.html [ Pass ]
-fast/css/001.html [ Pass ] 
+fast/css/001.html [ Pass ]
 fast/css/color-correction.html [ Pass ]
 fast/css-generated-content/001.html [ Pass ]
 fast/events/pointer-events-2.html [ Pass ]
@@ -637,8 +637,8 @@
 crbug.com/1179570 virtual/layout_ng_printing/printing/block-width-relayout-shrink.html [ Failure ]
 crbug.com/1179570 virtual/layout_ng_printing/printing/multicol-2-pages.html [ Failure ]
 crbug.com/1179570 virtual/layout_ng_printing/printing/thead-repeats-with-translucent-text-and-borders.html [ Failure ]
-crbug.com/1286601 virtual/layout_ng_printing/printing/vertical-lr.html [ Failure Crash ]
-crbug.com/1286601 virtual/layout_ng_printing/printing/vertical-rl.html [ Failure Crash ]
+crbug.com/1286601 virtual/layout_ng_printing/printing/vertical-lr.html [ Crash Failure ]
+crbug.com/1286601 virtual/layout_ng_printing/printing/vertical-rl.html [ Crash Failure ]
 crbug.com/1179570 virtual/off-main-thread-css-paint/http/tests/csspaint/entire-canvas-visible-zoom.html [ Failure ]
 crbug.com/1179570 virtual/off-main-thread-css-paint/http/tests/csspaint/geometry-background-image-zoom.html [ Failure ]
 crbug.com/1179570 virtual/off-main-thread-css-paint/http/tests/csspaint/geometry-border-image-zoom.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 5283b7b..b9a4842 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -7299,7 +7299,6 @@
 
 # FileSystemHandle::move() is temporarily disabled outside of the Origin Private File System
 crbug.com/1247850 external/wpt/file-system-access/local_FileSystemFileHandle-move-manual.https.html [ Failure ]
-crbug.com/1247850 external/wpt/file-system-access/local_FileSystemFileHandle-rename-manual.https.html [ Failure ]
 crbug.com/1247850 [ Fuchsia ] virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemFileHandle-move-manual.https.html [ Failure ]
 crbug.com/1247850 [ Linux ] virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemFileHandle-move-manual.https.html [ Failure ]
 crbug.com/1247850 [ Mac10.12 ] virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemFileHandle-move-manual.https.html [ Failure ]
@@ -7308,20 +7307,13 @@
 crbug.com/1247850 [ Mac10.15 ] virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemFileHandle-move-manual.https.html [ Failure ]
 crbug.com/1247850 [ Mac11 ] virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemFileHandle-move-manual.https.html [ Failure ]
 crbug.com/1247850 [ Win ] virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemFileHandle-move-manual.https.html [ Failure ]
-crbug.com/1247850 virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemFileHandle-rename-manual.https.html [ Failure ]
 # FileSystemHandle::move() is temporarily disabled for directory handles
 crbug.com/1250534 external/wpt/file-system-access/local_FileSystemDirectoryHandle-move-manual.https.html [ Failure ]
-crbug.com/1250534 external/wpt/file-system-access/local_FileSystemDirectoryHandle-rename-manual.https.html [ Failure ]
 crbug.com/1250534 external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-move.https.any.html [ Failure ]
-crbug.com/1250534 external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-rename.https.any.html [ Failure ]
 crbug.com/1250534 external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-move.https.any.worker.html [ Failure ]
-crbug.com/1250534 external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-rename.https.any.worker.html [ Failure ]
 crbug.com/1250534 virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemDirectoryHandle-move-manual.https.html [ Failure ]
-crbug.com/1250534 virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemDirectoryHandle-rename-manual.https.html [ Failure ]
 crbug.com/1250534 virtual/fsa-incognito/external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-move.https.any.html [ Failure ]
-crbug.com/1250534 virtual/fsa-incognito/external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-rename.https.any.html [ Failure ]
 crbug.com/1250534 virtual/fsa-incognito/external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-move.https.any.worker.html [ Failure ]
-crbug.com/1250534 virtual/fsa-incognito/external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-rename.https.any.worker.html [ Failure ]
 
 # Sheriff 2021-09-23
 crbug.com/1164568 [ Mac10.12 ] external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html [ Failure ]
@@ -7452,8 +7444,6 @@
 crbug.com/1267736 [ Win ] http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources.js [ Failure Pass ]
 
 # Sheriff 2021-11-09
-crbug.com/1268518 [ Linux ] external/wpt/web-animations/interfaces/Animation/onfinish.html [ Failure Pass ]
-crbug.com/1268518 [ Mac10.12 ] external/wpt/web-animations/interfaces/Animation/onfinish.html [ Failure Pass ]
 crbug.com/1269535 http/tests/misc/resource-timing-sizes-multipart.html [ Failure Pass Timeout ]
 crbug.com/1267734 [ Win7 ] fast/forms/suggestion-picker/week-suggestion-picker-appearance.html [ Failure Pass ]
 
@@ -7633,7 +7623,7 @@
 crbug.com/1280736 [ Win10.20h2 ] http/tests/inspector-protocol/network/blocked-setcookie-same-site-lax.js [ Pass Timeout ]
 
 # crbug.com/1285304 issues (Note - because color-scheme is in SlowTests, this must be Skip):
-crbug.com/1285304 fast/forms/color-scheme/suggestion-picker/time-suggestion-picker-appearance.html [ Skip Pass Failure Timeout ]
+crbug.com/1285304 fast/forms/color-scheme/suggestion-picker/time-suggestion-picker-appearance.html [ Failure Pass Skip Timeout ]
 
 # Sheriff 2022-01-04
 crbug.com/1283865 external/wpt/webmessaging/without-ports/020.html [ Failure Pass ]
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 45523ec7..856f5ad 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
@@ -97421,6 +97421,19 @@
        {}
       ]
      ],
+     "aspect-ratio-intrinsic-size-007.html": [
+      "5a6b896e97c365e16ba836dfdd1538e2dd9a3bff",
+      [
+       null,
+       [
+        [
+         "/css/css-flexbox/aspect-ratio-intrinsic-size-007-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "auto-height-column-with-border-and-padding.html": [
       "2151c21f61e915883a11bb78d7f785bdc5f5606c",
       [
@@ -229263,7 +229276,7 @@
       []
      ],
      "echo-ua-client-hints-received.py": [
-      "91cc606f3ca8970eb4f4b8cb3b0224c95adc2ffb",
+      "ea295ab210ab793e03e7c311578f958a59dd12c0",
       []
      ],
      "expect-client-hints-headers-iframe.py": [
@@ -232476,7 +232489,7 @@
      []
     ],
     "access-control-expose-headers-parsing.window-expected.txt": [
-     "0fe27f2fdca8ae7eeb0f92e9bef2717a6d8ac1d1",
+     "3000d57c8a13cceb01307f38d858245617fb50aa",
      []
     ],
     "resources": {
@@ -232489,7 +232502,7 @@
       []
      ],
      "access-control-expose-headers.json": [
-      "e8915f7ffe1533eb9b00292552ea216cc818c0ca",
+      "4ab38fbe09b7a3e8e648dcd0988706512429497c",
       []
      ],
      "cache-304.py": [
@@ -245358,6 +245371,10 @@
       "163efd401c4d24ce205dc9c39431b79598a7fb6f",
       []
      ],
+     "aspect-ratio-intrinsic-size-007-ref.html": [
+      "6d560db597fd312c69f14e90a2b74475dfe7a1a8",
+      []
+     ],
      "auto-margins-001-ref.html": [
       "57f4307ca0c60174495221d27d2a739f14a94abe",
       []
@@ -247311,6 +247328,10 @@
        "9945ef47114c2841a746c99a2fb1e93e050aac8b",
        []
       ],
+      "large-green-rectangle.svg": [
+       "228bb275c591f482ff8cd900491eaf8b1dd7b66d",
+       []
+      ],
       "pattern-grg-rgr-grg.png": [
        "9b88fbd81149891234185f54f8b4a0431759f181",
        []
@@ -262018,7 +262039,7 @@
        []
       ],
       "common.js": [
-       "7b91100b7719a15cdf430117525a7fd1ae984d13",
+       "f83122e837b943345b2f379f712df3d7ed6f53db",
        []
       ],
       "scroll-target-align-001-iframe.html": [
@@ -282374,7 +282395,7 @@
        []
       ],
       "record-header.py": [
-       "a9666033449f6300685d79118b2d2d827975bfd6",
+       "f2e7273c53c0755838f68f4d5748a8cb2f4388ac",
        []
       ],
       "redirectTestHelper.sub.js": [
@@ -304055,6 +304076,10 @@
      "563fa6720ba3a89d6ad8add86cd903465fe456f2",
      []
     ],
+    "MediaStreamTrackGenerator-in-worker.https-expected.txt": [
+     "11ecc9430dc08d3eceb70b8bacc693b955564dc2",
+     []
+    ],
     "MediaStreamTrackProcessor-worker.js": [
      "51eaef80a90a6e24fce8cad4fee03e05548e4517",
      []
@@ -309101,7 +309126,7 @@
       []
      ],
      "webxr-test.js": [
-      "8a541cae1b06f6bbda0b462ca618e565c76fba41",
+      "c3984ca8bbbdfc5677a0c28ce3b2e2401632a32a",
       []
      ],
      "webxr-test.js.headers": [
@@ -311418,7 +311443,7 @@
        []
       ],
       "fetch-event-handled-worker.js": [
-       "0dc6de005dba08cda134aa657e56191362cf28a8",
+       "53ee1493743d79768908a3ac4c47ca0b84243f4e",
        []
       ],
       "fetch-event-network-error-controllee-iframe.html": [
@@ -315561,7 +315586,7 @@
       []
      ],
      "urlpatterntestdata.json": [
-      "f20d62fdb540bc29ae5567c5dbe647f39681267a",
+      "671751fd3105b56ca0584553619c73634a971849",
       []
      ],
      "urlpatterntests.js": [
@@ -321823,7 +321848,7 @@
       []
      ],
      "webxr_test_constants.js": [
-      "7dbedd92419d14c212573e1b10c305c2034aea9a",
+      "042480da2bf1da718769fb2452a42da5cc3064f2",
       []
      ],
      "webxr_test_constants_fake_depth.js": [
@@ -321835,7 +321860,7 @@
       []
      ],
      "webxr_util.js": [
-      "75d73968ccaaca1411391f25b2726f6bda57e27d",
+      "625f76450e23dc509553a71b5a0157bccf91f8f6",
       []
      ]
     },
@@ -345596,7 +345621,7 @@
      ]
     ],
     "sec-ch-quotes.https.html": [
-     "d772ea8b5c3bb5ae852864fdc22b9a9e53c5bc9e",
+     "6a15b07276abec365acaa46ee26773bad4d0f08e",
      [
       null,
       {}
@@ -370429,6 +370454,15 @@
         }
        ]
       ],
+      "mouse-wheel.html": [
+       "287e594cab4be93210f13042c32300f83d5f7278",
+       [
+        null,
+        {
+         "testdriver": true
+        }
+       ]
+      ],
       "snap-area-overflow-boundary.html": [
        "ce9f73ef2393c06aefc7ee5ae2f265abea7c5cdf",
        [
@@ -415049,6 +415083,13 @@
      ]
     },
     "metadata": {
+     "audio-worklet.https.html": [
+      "3b768ef0b5ddd2d13361629afd011e6987cb38d0",
+      [
+       null,
+       {}
+      ]
+     ],
      "download.https.sub.html": [
       "6f2a0434d497f695a44cc0d8972083d7cfa194c9",
       [
@@ -415279,6 +415320,13 @@
        {}
       ]
      ],
+     "paint-worklet.https.html": [
+      "49fc7765f621752f5b3dfab713133514538cf8d9",
+      [
+       null,
+       {}
+      ]
+     ],
      "portal.https.sub.html": [
       "55b555a1b8ec4498f9dc897e3f64f09a2d61df93",
       [
@@ -454327,7 +454375,7 @@
         ]
        ],
        "selectmenu-keyboard.tentative.html": [
-        "4edf9336da410a8b561f304c0faf2be25c353e4f",
+        "9f937d7b7004e15e1ab74c04ae9b7a98afbdfa17",
         [
          null,
          {
@@ -454343,7 +454391,7 @@
         ]
        ],
        "selectmenu-many-options.tentative.html": [
-        "8de1318e61d0358f12419bd8e3b0587ca63165b7",
+        "442722fc087bf356fb26965695ae29f62f7167a7",
         [
          null,
          {
@@ -454379,7 +454427,7 @@
         ]
        ],
        "selectmenu-popup-position-with-zoom.tentative.html": [
-        "caf1bcf4d6c758b5097f31950166504633b32137",
+        "55ffbce99cb3db519d20f1798868dae8ce0465cc",
         [
          null,
          {
@@ -454388,7 +454436,7 @@
         ]
        ],
        "selectmenu-popup-position.tentative.html": [
-        "036c739fc3337b100e9dc87482a8f7b75ca1947e",
+        "559e3c9b9d834681af4c5b0a18dadaec7196b74b",
         [
          null,
          {
@@ -470405,6 +470453,13 @@
       }
      ]
     ],
+    "MediaStreamTrackGenerator-in-worker.https.html": [
+     "ff3b9459686d6507f89efb502b4d3436fff81f13",
+     [
+      null,
+      {}
+     ]
+    ],
     "MediaStreamTrackGenerator-video.https.html": [
      "a6f73f009c6d754d5f355e6492eb1623ab12591f",
      [
@@ -478369,10 +478424,12 @@
       ]
      ],
      "payment-report-only.https.html": [
-      "f5105c3b00041d8f77f4440bbefc95e6452aeb77",
+      "d4425f9f3ca559dc26996998bd043513671993d4",
       [
        null,
-       {}
+       {
+        "testdriver": true
+       }
       ]
      ],
      "payment-reporting.https.html": [
@@ -499108,7 +499165,7 @@
       ]
      ],
      "fetch-event-handled.https.html": [
-      "8d39b65bb628b8dcda07c804162583c80986a6c3",
+      "08b88ce3773d036cf1ea3a9f321f87b26d54fffd",
       [
        null,
        {}
@@ -542586,7 +542643,7 @@
      ]
     ],
     "streams-close.https.any.js": [
-     "be9a7322957596aa174b06c146e15e961d307aa5",
+     "4871ee8e7be0fbba33838b717554dc7eeb23337b",
      [
       "webtransport/streams-close.https.any.html",
       {
@@ -544835,6 +544892,13 @@
       {}
      ]
     ],
+    "xrViewerPose_secondaryViews.https.html": [
+     "446fedf14f353b241347d4deb9982981e6a3882f",
+     [
+      null,
+      {}
+     ]
+    ],
     "xrViewerPose_views_sameObject.https.html": [
      "af64111d8242d954acf29c123834833f12b16e96",
      [
@@ -544843,7 +544907,7 @@
      ]
     ],
     "xrViewport_valid.https.html": [
-     "4588a3fbc2bda8739b286509a931907c256b3e7c",
+     "c64c56cfdd6c18021f64e5b29014c09aacebb675",
      [
       null,
       {}
@@ -544892,14 +544956,14 @@
      ]
     ],
     "xrWebGLLayer_viewports.https.html": [
-     "74cc86f231b02ccc5590c7eedf9ee94974828c5d",
+     "8654e9e58708f4b056502905040f7dc2b0182aa7",
      [
       null,
       {}
      ]
     ],
     "xr_viewport_scale.https.html": [
-     "86e6f40005f43d845a547cce3404d5814f4839e8",
+     "a3e3a4e5bda2fb363e7d182984d21d4fad032872",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-007-ref.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-007-ref.html
new file mode 100644
index 0000000..6d560db
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-007-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<svg viewBox="0 0 1000 500" style="background: green"></svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-007.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-007.html
new file mode 100644
index 0000000..5a6b896
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-007.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#intrinsic-sizes">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#transferred-size-suggestion">
+<link rel="match" href="aspect-ratio-intrinsic-size-007-ref.html">
+<meta name="assert" content="This checks that an automatic preferred physical width is always considered definite whenever computing the transferred size suggestion. That size will be used instead of the flex-item's intrinsic size.">
+<div style="display: flex; flex-direction: column;">
+      <img src="support/large-green-rectangle.svg"/>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/large-green-rectangle.svg b/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/large-green-rectangle.svg
new file mode 100644
index 0000000..228bb27
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/support/large-green-rectangle.svg
@@ -0,0 +1,4 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg width="100%" height="100%" viewBox="0 0 7500 3750" version="1.1" xmlns="http://www.w3.org/2000/svg">
+    <rect id="Background" x="0" y="0" width="7500" height="3750" style="fill:green;"/>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-shorthand-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-shorthand-invalid.html
index 653b519..cdcbb4c5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-shorthand-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-shorthand-invalid.html
@@ -43,7 +43,9 @@
 test_invalid_value("grid", 'none / "a" []');
 test_invalid_value("grid", 'none / "a" [] 10px');
 test_invalid_value("grid", 'auto-flow 100px');
-
+test_invalid_value("grid", 'auto-flow / auto-flow');
+test_invalid_value("grid", 'auto-flow 1fr / auto-flow 1fr');
+test_invalid_value("grid", 'dense auto-flow / dense auto-flow');
 // FIXME: add more values to test full syntax
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-shorthand-valid.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-shorthand-valid.html
index 75f98da5..8d546a82 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-shorthand-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-shorthand-valid.html
@@ -54,12 +54,15 @@
 test_valid_value("grid", '"a" "a" [a] [a] "b" / auto', '"a" "a" [a a] "b" / auto');
 test_valid_value("grid", '100px / auto-flow dense 100px');
 test_valid_value("grid", 'auto-flow dense 1fr / 100px');
+test_valid_value("grid", '100px / dense auto-flow 100px', '100px / auto-flow dense 100px');
+test_valid_value("grid", 'dense auto-flow 1fr / 100px', 'auto-flow dense 1fr / 100px');
 test_valid_value("grid", '100px / auto-flow 100px');
 test_valid_value("grid", 'auto-flow 1fr / 100px');
 test_valid_value("grid", 'none / auto-flow 100px');
 test_valid_value("grid", 'auto-flow 1fr / none');
 test_valid_value("grid", 'auto / auto-flow 100px');
 test_valid_value("grid", 'auto-flow 1fr / auto');
+test_valid_value("grid", '1fr / 1fr');
 
 // FIXME: add more values to test full syntax
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-circle-offset-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-circle-offset-ref.html
new file mode 100644
index 0000000..5ba54fa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-circle-offset-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<svg>
+  <circle cx="80" cy="80" r="50" fill="green"/>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-circle-offset.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-circle-offset.html
new file mode 100644
index 0000000..155dbc2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-circle-offset.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>CSS Test: circle clip-path on svg graphics element with offset</title>
+<link rel="help" href="https://crbug.com/1286412">
+<link rel="help" href="https://drafts.fxtf.org/css-masking/#the-clip-path">
+<link rel="match" href="svg-clip-path-circle-offset-ref.html">
+<!-- Allow antialised pixel differences along the edge of the circle -->
+<meta name="fuzzy" content="0-10;0-200">
+<svg>
+  <rect x="30" y="30" width="100" height="100" fill="green" style="clip-path: circle(50%)"/>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-ellipse-offset-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-ellipse-offset-ref.html
new file mode 100644
index 0000000..75b867f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-ellipse-offset-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<svg>
+  <ellipse cx="80" cy="80" rx="40" ry="50" fill="green"/>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-ellipse-offset.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-ellipse-offset.html
new file mode 100644
index 0000000..c6329825
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/svg-clip-path-ellipse-offset.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>CSS Test: ellipse clip-path on svg graphics element with offset</title>
+<link rel="help" href="https://crbug.com/1286412">
+<link rel="help" href="https://drafts.fxtf.org/css-masking/#the-clip-path">
+<link rel="match" href="svg-clip-path-ellipse-offset-ref.html">
+<!-- Allow antialised pixel differences along the edge of the ellipse -->
+<meta name="fuzzy" content="0-10;0-200">
+<svg>
+  <rect x="30" y="30" width="100" height="100" fill="green" style="clip-path: ellipse(40% 50%)"/>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/local_FileSystemFileHandle-rename-manual.https.html b/third_party/blink/web_tests/external/wpt/file-system-access/local_FileSystemFileHandle-rename-manual.https.html
deleted file mode 100644
index 66771018..0000000
--- a/third_party/blink/web_tests/external/wpt/file-system-access/local_FileSystemFileHandle-rename-manual.https.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
-<script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/test-helpers.js"></script>
-<script src="resources/local-fs-test-helpers.js"></script>
-<script src="script-tests/FileSystemFileHandle-rename.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-rename.https.any.js b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-rename.https.any.js
deleted file mode 100644
index d6aa0d9f..0000000
--- a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemDirectoryHandle-rename.https.any.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// META: script=resources/test-helpers.js
-// META: script=resources/sandboxed-fs-test-helpers.js
-// META: script=script-tests/FileSystemDirectoryHandle-rename.js
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemFileHandle-rename.https.any.js b/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemFileHandle-rename.https.any.js
deleted file mode 100644
index 37039b83..0000000
--- a/third_party/blink/web_tests/external/wpt/file-system-access/sandboxed_FileSystemFileHandle-rename.https.any.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// META: script=resources/test-helpers.js
-// META: script=resources/sandboxed-fs-test-helpers.js
-// META: script=script-tests/FileSystemFileHandle-rename.js
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemDirectoryHandle-move.js b/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemDirectoryHandle-move.js
index 368e76ee4..856c1f3 100644
--- a/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemDirectoryHandle-move.js
+++ b/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemDirectoryHandle-move.js
@@ -4,6 +4,32 @@
 
 directory_test(async (t, root) => {
   const dir = await root.getDirectoryHandle('dir-before', {create: true});
+  await dir.move('dir-after');
+
+  assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
+  assert_array_equals(await getSortedDirectoryEntries(dir), []);
+}, 'move(name) to rename an empty directory');
+
+directory_test(async (t, root) => {
+  const dir = await root.getDirectoryHandle('dir-before', {create: true});
+  await promise_rejects_js(t, TypeError, dir.move(''));
+
+  assert_array_equals(await getSortedDirectoryEntries(root), ['dir-before/']);
+  assert_array_equals(await getSortedDirectoryEntries(dir), []);
+}, 'move("") to rename an empty directory fails');
+
+directory_test(async (t, root) => {
+  const dir = await root.getDirectoryHandle('dir-before', {create: true});
+  await createFileWithContents(t, 'file-in-dir', 'abc', dir);
+  await dir.move('dir-after');
+
+  assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
+  assert_array_equals(await getSortedDirectoryEntries(dir), ['file-in-dir']);
+}, 'move(name) to rename a non-empty directory');
+
+
+directory_test(async (t, root) => {
+  const dir = await root.getDirectoryHandle('dir-before', {create: true});
   await dir.move(root, 'dir-after');
 
   assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemDirectoryHandle-rename.js b/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemDirectoryHandle-rename.js
deleted file mode 100644
index 315303b0..0000000
--- a/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemDirectoryHandle-rename.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// META: script=resources/test-helpers.js
-
-'use strict';
-
-directory_test(async (t, root) => {
-  const dir = await root.getDirectoryHandle('dir-before', {create: true});
-  await dir.rename('dir-after');
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
-  assert_array_equals(await getSortedDirectoryEntries(dir), []);
-}, 'rename(name) to rename an empty directory');
-
-directory_test(async (t, root) => {
-  const dir = await root.getDirectoryHandle('dir-before', {create: true});
-  await promise_rejects_js(t, TypeError, dir.rename(''));
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['dir-before/']);
-  assert_array_equals(await getSortedDirectoryEntries(dir), []);
-}, 'rename("") to rename an empty directory fails');
-
-directory_test(async (t, root) => {
-  const dir = await root.getDirectoryHandle('dir-before', {create: true});
-  await createFileWithContents(t, 'file-in-dir', 'abc', dir);
-  await dir.rename('dir-after');
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
-  assert_array_equals(await getSortedDirectoryEntries(dir), ['file-in-dir']);
-}, 'rename(name) to rename a non-empty directory');
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemFileHandle-move.js b/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemFileHandle-move.js
index 31fa55c..a3be9f4 100644
--- a/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemFileHandle-move.js
+++ b/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemFileHandle-move.js
@@ -4,6 +4,97 @@
 
 directory_test(async (t, root) => {
   const handle = await createFileWithContents(t, 'file-before', 'foo', root);
+  await handle.move('file-after');
+
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-after']);
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+}, 'move(name) to rename a file');
+
+directory_test(async (t, root) => {
+  const handle = await createFileWithContents(t, 'file-before', 'foo', root);
+  await handle.move('file-before');
+
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+}, 'move(name) to rename a file the same name');
+
+directory_test(async (t, root) => {
+  const handle = await createFileWithContents(t, 'file-before', 'foo', root);
+  await promise_rejects_js(t, TypeError, handle.move(''));
+
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+}, 'move("") to rename a file fails');
+
+directory_test(async (t, root) => {
+  const handle = await createFileWithContents(t, 'file-1', 'foo', root);
+
+  await handle.move('file-2');
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-2']);
+
+  await handle.move('file-3');
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-3']);
+
+  await handle.move('file-1');
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-1']);
+}, 'move(name) can be called multiple times');
+
+directory_test(async (t, root) => {
+  const dir = await root.getDirectoryHandle('dir', {create: true});
+  const handle = await createFileWithContents(t, 'file-before', 'foo', dir);
+  await promise_rejects_js(t, TypeError, handle.move('Lorem.'));
+
+  assert_array_equals(await getSortedDirectoryEntries(root), ['dir/']);
+  assert_array_equals(await getSortedDirectoryEntries(dir), ['file-before']);
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+}, 'move(name) with a name with a trailing period should fail');
+
+directory_test(async (t, root) => {
+  const handle = await createFileWithContents(t, 'file-before', 'foo', root);
+  await promise_rejects_js(t, TypeError, handle.move('#$23423@352^*3243'));
+
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+}, 'move(name) with a name with invalid characters should fail');
+
+directory_test(async (t, root) => {
+  const handle = await createFileWithContents(t, 'file-before', 'abc', root);
+
+  // Cannot rename handle with an active writable.
+  const stream = await handle.createWritable();
+  await promise_rejects_dom(
+      t, 'NoModificationAllowedError', handle.move('file-after'));
+
+  // Can move handle once the writable is closed.
+  await stream.close();
+  await handle.move('file-after');
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-after']);
+}, 'move(name) while the file has an open writable fails');
+
+directory_test(async (t, root) => {
+  const handle = await createFileWithContents(t, 'file-before', 'abc', root);
+  const handle_dest =
+      await createFileWithContents(t, 'file-after', '123', root);
+
+  // Cannot overwrite a handle with an active writable.
+  const stream = await handle_dest.createWritable();
+  await promise_rejects_dom(
+      t, 'NoModificationAllowedError', handle.move('file-after'));
+
+  // Can move handle once the writable is closed.
+  await stream.close();
+  await handle.move('file-after');
+  assert_array_equals(await getSortedDirectoryEntries(root), ['file-after']);
+}, 'move(name) while the destination file has an open writable fails');
+
+
+directory_test(async (t, root) => {
+  const handle = await createFileWithContents(t, 'file-before', 'foo', root);
   await handle.move(root, 'file-after');
 
   assert_array_equals(await getSortedDirectoryEntries(root), ['file-after']);
diff --git a/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemFileHandle-rename.js b/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemFileHandle-rename.js
deleted file mode 100644
index 94ca020..0000000
--- a/third_party/blink/web_tests/external/wpt/file-system-access/script-tests/FileSystemFileHandle-rename.js
+++ /dev/null
@@ -1,106 +0,0 @@
-// META: script=resources/test-helpers.js
-
-'use strict';
-
-directory_test(async (t, root) => {
-  const handle = await createFileWithContents(t, 'file-before', 'foo', root);
-  await handle.rename('file-after');
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-after']);
-  assert_equals(await getFileContents(handle), 'foo');
-  assert_equals(await getFileSize(handle), 3);
-}, 'rename(name) to rename a file');
-
-directory_test(async (t, root) => {
-  const handle = await createFileWithContents(t, 'file-before', 'foo', root);
-  await handle.rename('file-before');
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
-  assert_equals(await getFileContents(handle), 'foo');
-  assert_equals(await getFileSize(handle), 3);
-}, 'rename(name) to rename a file the same name');
-
-directory_test(async (t, root) => {
-  const handle = await createFileWithContents(t, 'file-before', 'foo', root);
-  await promise_rejects_js(t, TypeError, handle.rename(''));
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
-  assert_equals(await getFileContents(handle), 'foo');
-  assert_equals(await getFileSize(handle), 3);
-}, 'rename("") to rename a file fails');
-
-directory_test(async (t, root) => {
-  const handle = await createFileWithContents(t, 'file-1', 'foo', root);
-
-  await handle.rename('file-2');
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-2']);
-
-  await handle.rename('file-3');
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-3']);
-
-  await handle.rename('file-1');
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-1']);
-}, 'rename(name) can be called multiple times');
-
-directory_test(async (t, root) => {
-  const dir = await root.getDirectoryHandle('dir', {create: true});
-  const handle = await createFileWithContents(t, 'file-before', 'foo', dir);
-  await handle.rename(root);
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['dir/']);
-  assert_array_equals(
-      await getSortedDirectoryEntries(dir),
-      ['[object FileSystemDirectoryHandle]']);
-  assert_equals(await getFileContents(handle), 'foo');
-  assert_equals(await getFileSize(handle), 3);
-}, 'rename(dir) should rename to stringified dir object');
-
-directory_test(async (t, root) => {
-  const dir = await root.getDirectoryHandle('dir', {create: true});
-  const handle = await createFileWithContents(t, 'file-before', 'foo', dir);
-  await promise_rejects_js(t, TypeError, handle.rename('Lorem.'));
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['dir/']);
-  assert_array_equals(await getSortedDirectoryEntries(dir), ['file-before']);
-  assert_equals(await getFileContents(handle), 'foo');
-  assert_equals(await getFileSize(handle), 3);
-}, 'rename(name) with a name with a trailing period should fail');
-
-directory_test(async (t, root) => {
-  const handle = await createFileWithContents(t, 'file-before', 'foo', root);
-  await promise_rejects_js(t, TypeError, handle.rename('#$23423@352^*3243'));
-
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
-  assert_equals(await getFileContents(handle), 'foo');
-  assert_equals(await getFileSize(handle), 3);
-}, 'rename(name) with a name with invalid characters should fail');
-
-directory_test(async (t, root) => {
-  const handle = await createFileWithContents(t, 'file-before', 'abc', root);
-
-  // Cannot rename handle with an active writable.
-  const stream = await handle.createWritable();
-  await promise_rejects_dom(
-      t, 'NoModificationAllowedError', handle.rename('file-after'));
-
-  // Can move handle once the writable is closed.
-  await stream.close();
-  await handle.rename('file-after');
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-after']);
-}, 'rename(name) while the file has an open writable fails');
-
-directory_test(async (t, root) => {
-  const handle = await createFileWithContents(t, 'file-before', 'abc', root);
-  const handle_dest =
-      await createFileWithContents(t, 'file-after', '123', root);
-
-  // Cannot overwrite a handle with an active writable.
-  const stream = await handle_dest.createWritable();
-  await promise_rejects_dom(
-      t, 'NoModificationAllowedError', handle.rename('file-after'));
-
-  // Can move handle once the writable is closed.
-  await stream.close();
-  await handle.rename('file-after');
-  assert_array_equals(await getSortedDirectoryEntries(root), ['file-after']);
-}, 'rename(name) while the destination file has an open writable fails');
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/anonymous-window.tentative.https.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/anonymous-window.tentative.https.js
new file mode 100644
index 0000000..dc63dc26
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/anonymous-window.tentative.https.js
@@ -0,0 +1,48 @@
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=../credentialless/resources/common.js
+
+const ORIGIN = get_host_info();
+
+promise_test_parallel(async t => {
+  const iframe = document.createElement("iframe");
+  document.body.appendChild(iframe);
+  iframe.contentWindow.modified = true;
+  iframe.anonymous = true;
+  iframe.src = ORIGIN + "/blank.html";
+  // Wait for navigation finished.
+  await t.step_wait(() =>
+    iframe.contentWindow.location.href === iframe.src,
+    "Wait for the navigation to complete");
+  assert_true(iframe.anonymous);
+  assert_equals(undefined, iframe.contentWindow.modified);
+}, "Anonymous (false => true) => window not reused.");
+
+promise_test_parallel(async t => {
+  const iframe = document.createElement("iframe");
+  iframe.anonymous = true;
+  document.body.appendChild(iframe);
+  iframe.contentWindow.modified = true;
+  iframe.anonymous = false;
+  iframe.src = ORIGIN + "/blank.html";
+  // Wait for navigation finished.
+  await t.step_wait(() =>
+    iframe.contentWindow.location.href === iframe.src,
+    "Wait for the navigation to complete");
+  assert_false(iframe.anonymous);
+  assert_equals(undefined, iframe.contentWindow.modified);
+}, "Anonymous (true => false) => window not reused.");
+
+promise_test_parallel(async t => {
+  const iframe = document.createElement("iframe");
+  iframe.anonymous = true;
+  document.body.appendChild(iframe);
+  iframe.contentWindow.modified = true;
+  iframe.src = ORIGIN + "/blank.html";
+  // Wait for navigation finished.
+  await t.step_wait(() =>
+    iframe.contentWindow.location.href === iframe.src,
+    "Wait for the navigation to complete");
+  assert_true(iframe.anonymous);
+  assert_true(iframe.contentWindow.modified);
+}, "Anonymous (true => true) => window reused.");
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/broadcast-channel.tentative.window.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/broadcast-channel.tentative.window.js
deleted file mode 100644
index 255a71920..0000000
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/anonymous-iframe/broadcast-channel.tentative.window.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// META: script=/common/get-host-info.sub.js
-// META: script=/common/utils.js
-// META: script=/common/dispatcher/dispatcher.js
-// META: script=../credentialless/resources/common.js
-// META: script=./resources/common.js
-
-// A script listening using a BroadcastChannel.
-const listen_script = (key, done, onmessage) => `
-  const bc = new BroadcastChannel("${key}");
-  bc.onmessage = event => send("${onmessage}", event.data);
-  send("${done}", "registered");
-`;
-
-const emit_script = (key, message) => `
-  const bc = new BroadcastChannel("${key}");
-  bc.postMessage("${message}");
-`;
-
-promise_test(async test => {
-  const origin = get_host_info().HTTPS_REMOTE_ORIGIN;
-  const key_1 = token();
-  const key_2 = token();
-
-  // 2 actors: An anonymous iframe and a normal one.
-  const iframe_anonymous = newAnonymousIframe(origin);
-  const iframe_normal = newIframe(origin);
-  const queue_1 = token();
-  const queue_2 = token();
-  const unexpected_queue = token();
-
-  // Listen using the two keys from both sides:
-  send(iframe_anonymous , listen_script(key_1, queue_1, queue_1));
-  send(iframe_anonymous , listen_script(key_2, queue_1, unexpected_queue));
-  send(iframe_normal, listen_script(key_2, queue_2, queue_2));
-  send(iframe_normal, listen_script(key_1, queue_2, unexpected_queue));
-  assert_equals(await receive(queue_1), "registered");
-  assert_equals(await receive(queue_1), "registered");
-  assert_equals(await receive(queue_2), "registered");
-  assert_equals(await receive(queue_2), "registered");
-
-  // Emit from both sides. It must work, and work without crossing the
-  // anonymous/non-anonymous border.
-  receive(unexpected_queue).then(test.unreached_func(
-    "BroadcastChannel shouldn't cross the anonymous/normal border"));
-  send(iframe_anonymous , emit_script(key_1, "msg_1"));
-  send(iframe_normal, emit_script(key_2, "msg_2"));
-  assert_equals(await receive(queue_1), "msg_1");
-  assert_equals(await receive(queue_2), "msg_2");
-
-  // Wait a bit to let bad things the opportunity to show up. This is done by
-  // repeating the previous operation.
-  send(iframe_anonymous , emit_script(key_1, "msg_3"));
-  send(iframe_normal, emit_script(key_2, "msg_4"));
-  assert_equals(await receive(queue_1), "msg_3");
-  assert_equals(await receive(queue_2), "msg_4");
-})
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/resets-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/resets-expected.txt
index 73ad4ec..892483f 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/resets-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/resets-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 310 tests; 304 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 310 tests; 305 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS <input type="hidden"> - letter-spacing
 PASS <input type="hidden"> - word-spacing
 PASS <input type="hidden"> - line-height
@@ -274,7 +274,7 @@
 PASS <table><tbody><tr><td> - text-shadow
 PASS <table><tbody><tr><td> - text-align
 PASS <table><tbody><tr><td> - display
-FAIL <table><tbody><tr><td> - box-sizing assert_equals: expected "content-box" but got "border-box"
+PASS <table><tbody><tr><td> - box-sizing
 PASS <tbody><tr><td> (in <table>) - letter-spacing
 PASS <tbody><tr><td> (in <table>) - word-spacing
 PASS <tbody><tr><td> (in <table>) - line-height
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/resets.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/resets.html
index 8576817..20d6a56 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/resets.html
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/resets.html
@@ -48,7 +48,7 @@
 marquee {
   text-align: initial;
 }
-table { display: table; }
+table { display: table; box-sizing: border-box; }
 caption { display: table-caption; }
 colgroup, colgroup[hidden] { display: table-column-group; }
 col, col[hidden] { display: table-column; }
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-scroll-height.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-scroll-height.html
index 2169e5d..638217f 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-scroll-height.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-scroll-height.html
@@ -27,6 +27,6 @@
 <script>
 test(() => {
   document.querySelector('dialog').showModal();
-  assert_equals(document.scrollingElement.scrollHeight, 600);
+  assert_equals(document.scrollingElement.scrollHeight, window.innerHeight);
 }, 'dialogs should be centered before computing overflow.');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/non-html-documents.html b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/non-html-documents.html
new file mode 100644
index 0000000..d86cf48
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/non-html-documents.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<title>Allow text fragments in HTML documents only</title>
+<meta charset=utf-8>
+<link rel="help" href="https://wicg.github.io/ScrollToTextFragment/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/common/utils.js"></script>
+<script src="stash.js"></script>
+
+<script>
+function rAF(win) {
+  return new Promise((resolve) => {
+    win.requestAnimationFrame(resolve);
+  });
+}
+
+function openPopup(url) {
+  return new Promise((resolve) => {
+    test_driver.bless('Open a URL with a text fragment directive', () => {
+      const popup = window.open(url, '_blank', 'width=300,height=300');
+      popup.onload = () => resolve(popup);
+    });
+  });
+}
+
+const test_cases = [
+  'non-html.css',
+  'non-html.js',
+  'non-html.json',
+  'non-html.txt',
+  'non-html.xml'
+];
+
+for (let test_case of test_cases) {
+  promise_test(async function (t) {
+    const popup = await openPopup(`resources/${test_case}#:~:text=target`);
+
+    // rAF twice in case there is any asynchronicity in scrolling to the target.
+    await rAF(popup);
+    await rAF(popup);
+
+    assert_equals(popup.scrollY, 0);
+    popup.close();
+  }, `Text directive blocked in ${test_case}`);
+}
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.css b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.css
new file mode 100644
index 0000000..07f0294
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.css
@@ -0,0 +1,132 @@
+
+      :root {
+        font-family: system-ui;
+      }
+      .valueFlex {
+        width: 100%;
+        box-sizing: border-box;
+        height: 40px;
+        border: 1px solid grey;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        gap: 10px;
+        background-color: lightgrey;
+
+      }
+      .valueFlex div {
+        height: 100%;
+        flex-grow: 1;
+      }
+      .valueFlex .value {
+        flex-grow: 4;
+        text-align: center;
+      }
+
+      .valueFlex div div {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+
+      .valueFlex .value.disabled {
+        background-color: tomato;
+      }
+      .valueFlex .value.disabled div:before {
+        content: "Disabled";
+      }
+
+      .valueFlex .value.enabled {
+        background-color: chartreuse;
+      }
+      .valueFlex .value.enabled div:before {
+        content: "Enabled";
+      }
+
+      .valueGrid {
+        border: 1px solid grey;
+        display: grid;
+        grid-template-columns: 1fr 3fr;
+      }
+
+      .valueGrid>div {
+        padding: 5px;
+        background-color: lightgrey;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+
+      .valueGrid>div>div {
+        overflow-wrap: anywhere;
+      }
+
+      .valueGrid div.value {
+        background-color: thistle;
+      }
+
+      .generator {
+        width: 100%;
+        box-sizing: border-box;
+        height: 40px;
+        border: 1px solid grey;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        gap: 10px;
+        background-color: lightgrey;
+      }
+
+      .items {
+        display: grid;
+        grid-template-columns: 1fr 4fr;
+        gap: 4px;
+      }
+
+      .box {
+        border: 1px solid black;
+      }
+
+      .box.label {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+
+      .box.listing {
+        padding: 10px;
+        display: grid;
+        grid-template-columns: 1fr 4fr;
+        row-gap: 2px;
+      }
+
+      .box.listing div {
+        background-color: lightgrey;
+      }
+      .box.listing .value {
+        font-style: italic;
+        overflow-wrap: anywhere;
+      }
+
+      .content {
+      }
+
+      hr {
+        margin-top: 40px;
+        margin-bottom: 40px;
+      }
+
+      #iframesContainer {
+        display:flex;
+        width: 100%;
+        border: 1px solid blue;
+      }
+
+      #iframesContainer div {
+        flex: 1;
+      }
+
+      #target {
+        width: 100px;
+      }
+
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.js b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.js
new file mode 100644
index 0000000..b75d40dc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.js
@@ -0,0 +1,31 @@
+// Taken from https://en.wikipedia.org/wiki/JavaScript
+
+// Declares a function-scoped variable named `x`, and implicitly assigns the
+// special value `undefined` to it. Variables without value are automatically
+// set to undefined.
+var x;
+
+// Variables can be manually set to `undefined` like so
+var x2 = undefined;
+
+// Declares a block-scoped variable named `y`, and implicitly sets it to
+// `undefined`. The `let` keyword was introduced in ECMAScript 2015.
+let y;
+
+// Declares a block-scoped, un-reassignable variable named `z`, and sets it to
+// a string literal. The `const` keyword was also introduced in ECMAScript 2015,
+// and must be explicitly assigned to.
+
+// The keyword `const` means constant, hence the variable cannot be reassigned
+// as the value is `constant`.
+const z = "this value cannot be reassigned!";
+
+// Declares a variable named `myNumber`, and assigns a number literal (the value
+// `2`) to it.
+let myNumber = 2;
+
+// Reassigns `myNumber`, setting it to a string literal (the value `"foo"`).
+// JavaScript is a dynamically-typed language, so this is legal.
+myNumber = "foo";
+
+const target = "foo";
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.json b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.json
new file mode 100644
index 0000000..46fedf8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.json
@@ -0,0 +1,102 @@
+{
+  "from":"https://json.org/example.html",
+  "web-app":{
+    "servlet":[
+      {
+        "servlet-name":"cofaxCDS",
+        "servlet-class":"org.cofax.cds.CDSServlet",
+        "init-param":{
+          "configGlossary:installationAt":"Philadelphia, PA",
+          "configGlossary:adminEmail":"ksm@pobox.com",
+          "configGlossary:poweredBy":"Cofax",
+          "configGlossary:poweredByIcon":"/images/cofax.gif",
+          "configGlossary:staticPath":"/content/static",
+          "templateProcessorClass":"org.cofax.WysiwygTemplate",
+          "templateLoaderClass":"org.cofax.FilesTemplateLoader",
+          "templatePath":"templates",
+          "templateOverridePath":"",
+          "defaultListTemplate":"listTemplate.htm",
+          "defaultFileTemplate":"articleTemplate.htm",
+          "useJSP":false,
+          "jspListTemplate":"listTemplate.jsp",
+          "jspFileTemplate":"articleTemplate.jsp",
+          "cachePackageTagsTrack":200,
+          "cachePackageTagsStore":200,
+          "cachePackageTagsRefresh":60,
+          "cacheTemplatesTrack":100,
+          "cacheTemplatesStore":50,
+          "cacheTemplatesRefresh":15,
+          "cachePagesTrack":200,
+          "cachePagesStore":100,
+          "cachePagesRefresh":10,
+          "cachePagesDirtyRead":10,
+          "searchEngineListTemplate":"forSearchEnginesList.htm",
+          "searchEngineFileTemplate":"forSearchEngines.htm",
+          "searchEngineRobotsDb":"WEB-INF/robots.db",
+          "useDataStore":true,
+          "dataStoreClass":"org.cofax.SqlDataStore",
+          "redirectionClass":"org.cofax.SqlRedirection",
+          "dataStoreName":"cofax",
+          "dataStoreDriver":"com.microsoft.jdbc.sqlserver.SQLServerDriver",
+          "dataStoreUrl":"jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
+          "dataStoreUser":"sa",
+          "dataStorePassword":"dataStoreTestQuery",
+          "dataStoreTestQuery":"SET NOCOUNT ON;select test='test';",
+          "dataStoreLogFile":"/usr/local/tomcat/logs/datastore.log",
+          "dataStoreInitConns":10,
+          "dataStoreMaxConns":100,
+          "dataStoreConnUsageLimit":100,
+          "dataStoreLogLevel":"debug",
+          "maxUrlLength":500
+        }
+      },
+      {
+        "servlet-name":"cofaxEmail",
+        "servlet-class":"org.cofax.cds.EmailServlet",
+        "init-param":{
+          "mailHost":"mail1",
+          "mailHostOverride":"mail2"
+        }
+      },
+      {
+        "servlet-name":"cofaxAdmin",
+        "servlet-class":"org.cofax.cds.AdminServlet"
+      },
+      {
+        "servlet-name":"fileServlet",
+        "servlet-class":"org.cofax.cds.FileServlet"
+      },
+      {
+        "servlet-name":"cofaxTools",
+        "servlet-class":"org.cofax.cms.CofaxToolsServlet",
+        "init-param":{
+          "templatePath":"toolstemplates/",
+          "log":1,
+          "logLocation":"/usr/local/tomcat/logs/CofaxTools.log",
+          "logMaxSize":"",
+          "dataLog":1,
+          "dataLogLocation":"/usr/local/tomcat/logs/dataLog.log",
+          "dataLogMaxSize":"",
+          "removePageCache":"/content/admin/remove?cache=pages&id=",
+          "removeTemplateCache":"/content/admin/remove?cache=templates&id=",
+          "fileTransferFolder":"/usr/local/tomcat/webapps/content/fileTransferFolder",
+          "lookInContext":1,
+          "adminGroupID":4,
+          "betaServer":true
+        }
+      }
+    ],
+    "servlet-mapping":{
+      "cofaxCDS":"/",
+      "cofaxEmail":"/cofaxutil/aemail/*",
+      "cofaxAdmin":"/admin/*",
+      "fileServlet":"/static/*",
+      "cofaxTools":"/tools/*"
+    },
+    "taglib":{
+      "taglib-uri":"cofax.tld",
+      "taglib-location":"/WEB-INF/tlds/cofax.tld",
+      "target": "foo"
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.txt b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.txt
new file mode 100644
index 0000000..785a4d56
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.txt
@@ -0,0 +1,25 @@
+For its first five years (1990-1995), HTML went through a number of revisions and experienced a number of extensions, primarily hosted first at CERN, and then at the IETF.
+
+With the creation of the W3C, HTML's development changed venue again. A first abortive attempt at extending HTML in 1995 known as HTML 3.0 then made way to a more pragmatic approach known as HTML 3.2, which was completed in 1997. HTML4 quickly followed later that same year.
+
+The following year, the W3C membership decided to stop evolving HTML and instead begin work on an XML-based equivalent, called XHTML. This effort started with a reformulation of HTML4 in XML, known as XHTML 1.0, which added no new features except the new serialization, and which was completed in 2000. After XHTML 1.0, the W3C's focus turned to making it easier for other working groups to extend XHTML, under the banner of XHTML Modularization. In parallel with this, the W3C also worked on a new language that was not compatible with the earlier HTML and XHTML languages, calling it XHTML2.
+
+Around the time that HTML's evolution was stopped in 1998, parts of the API for HTML developed by browser vendors were specified and published under the name DOM Level 1 (in 1998) and DOM Level 2 Core and DOM Level 2 HTML (starting in 2000 and culminating in 2003). These efforts then petered out, with some DOM Level 3 specifications published in 2004 but the working group being closed before all the Level 3 drafts were completed.
+
+In 2003, the publication of XForms, a technology which was positioned as the next generation of web forms, sparked a renewed interest in evolving HTML itself, rather than finding replacements for it. This interest was borne from the realization that XML's deployment as a web technology was limited to entirely new technologies (like RSS and later Atom), rather than as a replacement for existing deployed technologies (like HTML).
+
+A proof of concept to show that it was possible to extend HTML4's forms to provide many of the features that XForms 1.0 introduced, without requiring browsers to implement rendering engines that were incompatible with existing HTML web pages, was the first result of this renewed interest. At this early stage, while the draft was already publicly available, and input was already being solicited from all sources, the specification was only under Opera Software's copyright.
+
+The idea that HTML's evolution should be reopened was tested at a W3C workshop in 2004, where some of the principles that underlie the HTML5 work (described below), as well as the aforementioned early draft proposal covering just forms-related features, were presented to the W3C jointly by Mozilla and Opera. The proposal was rejected on the grounds that the proposal conflicted with the previously chosen direction for the web's evolution; the W3C staff and membership voted to continue developing XML-based replacements instead.
+
+Shortly thereafter, Apple, Mozilla, and Opera jointly announced their intent to continue working on the effort under the umbrella of a new venue called the WHATWG. A public mailing list was created, and the draft was moved to the WHATWG site. The copyright was subsequently amended to be jointly owned by all three vendors, and to allow reuse of the specification.
+
+The WHATWG was based on several core principles, in particular that technologies need to be backwards compatible, that specifications and implementations need to match even if this means changing the specification rather than the implementations, and that specifications need to be detailed enough that implementations can achieve complete interoperability without reverse-engineering each other.
+
+The latter requirement in particular required that the scope of the HTML5 specification include what had previously been specified in three separate documents: HTML4, XHTML1, and DOM2 HTML. It also meant including significantly more detail than had previously been considered the norm.
+
+In 2006, the W3C indicated an interest to participate in the development of HTML5 after all, and in 2007 formed a working group chartered to work with the WHATWG on the development of the HTML5 specification. Apple, Mozilla, and Opera allowed the W3C to publish the specification under the W3C copyright, while keeping a version with the less restrictive license on the WHATWG site.
+
+For a number of years, both groups then worked together. In 2011, however, the groups came to the conclusion that they had different goals: the W3C wanted to publish a "finished" version of "HTML5", while the WHATWG wanted to continue working on a Living Standard for HTML, continuously maintaining the specification rather than freezing it in a state with known problems, and adding new features as needed to evolve the platform.
+
+In 2019, the WHATWG and W3C signed an agreement to collaborate on a single version of HTML going forward: this document.
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.xml b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.xml
new file mode 100644
index 0000000..e938de2a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/resources/non-html.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<messages>
+  <message>
+     Hello World
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     The quick brown dog jumped over the lazy fox
+  </message>
+  <message>
+     Target
+  </message>
+</messages>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-event-handled.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-event-handled.https.html
index 8d39b65b..08b88ce 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-event-handled.https.html
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-event-handled.https.html
@@ -10,18 +10,11 @@
 let worker = null;
 const script = 'resources/fetch-event-handled-worker.js';
 const scope = 'resources/simple.html';
+const channel = new MessageChannel();
 
 // Wait for a message from the service worker and removes the message handler.
 function wait_for_message_from_worker() {
-  return new Promise((resolve) => {
-    const handler = (event) => {
-      frame.contentWindow.navigator.serviceWorker.removeEventListener(
-          'message', handler);
-      resolve(event.data);
-    };
-    frame.contentWindow.navigator.serviceWorker.addEventListener(
-        'message', handler);
-  });
+  return new Promise((resolve) => channel.port2.onmessage = (event) => resolve(event.data));
 }
 
 // Global setup: this must be the first promise_test.
@@ -29,12 +22,16 @@
   const registration =
       await service_worker_unregister_and_register(t, script, scope);
   worker = registration.installing;
+  if (!worker)
+      worker = registration.active;
+  worker.postMessage({port:channel.port1}, [channel.port1]);
   await wait_for_state(t, worker, 'activated');
 }, 'global setup');
 
 promise_test(async (t) => {
-  frame = await with_iframe(scope);
+  const promise = with_iframe(scope);
   const message = await wait_for_message_from_worker();
+  frame = await promise;
   assert_equals(message, 'RESOLVED');
 }, 'FetchEvent.handled should resolve when respondWith() is not called for a' +
     ' navigation request');
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-event-handled-worker.js b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-event-handled-worker.js
index 0dc6de0..53ee1493 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-event-handled-worker.js
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-event-handled-worker.js
@@ -1,25 +1,19 @@
 // This worker reports back the final state of FetchEvent.handled (RESOLVED or
 // REJECTED) to the test.
 
-// Send a message to the client with the client id.
-function send_message_to_client(message, clientId) {
-  clients.get(clientId).then((client) => {
-    client.postMessage(message);
-  });
-}
+self.addEventListener('message', function(event) {
+  self.port = event.data.port;
+});
 
 self.addEventListener('fetch', function(event) {
-  const clientId = (event.request.mode === 'navigate') ?
-      event.resultingClientId : event.clientId;
-
   try {
     event.handled.then(() => {
-      send_message_to_client('RESOLVED', clientId);
+      self.port.postMessage('RESOLVED');
     }, () => {
-      send_message_to_client('REJECTED', clientId);
+      self.port.postMessage('REJECTED');
     });
   } catch (e) {
-    send_message_to_client('FAILED', clientId);
+    self.port.postMessage('FAILED');
     return;
   }
 
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
index 4c135c6..6b85195 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -2,6 +2,7 @@
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
+PASS oldChildWindow.anonymous is newChildWindow.anonymous
 PASS oldChildWindow.appHistory.canGoBack is newChildWindow.appHistory.canGoBack
 PASS oldChildWindow.appHistory.canGoForward is newChildWindow.appHistory.canGoForward
 PASS oldChildWindow.appHistory.current is newChildWindow.appHistory.current
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
index 80f811d..a7b3615 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -2,6 +2,7 @@
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
+PASS childWindow.anonymous is false
 PASS childWindow.appHistory.canGoBack is false
 PASS childWindow.appHistory.canGoForward is false
 PASS childWindow.appHistory.current is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
index a9a472e..c217152 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -2,6 +2,7 @@
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
+PASS childWindow.anonymous is false
 PASS childWindow.appHistory.canGoBack is false
 PASS childWindow.appHistory.canGoForward is false
 PASS childWindow.appHistory.current is null
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 5d302eab..e04c549 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -544,7 +544,6 @@
     method createWritable
     method getFile
     method move
-    method rename
 interface FileSystemHandle
     attribute @@toStringTag
     getter kind
@@ -554,7 +553,6 @@
     method move
     method queryPermission
     method remove
-    method rename
     method requestPermission
 interface FileSystemWritableFileStream : WritableStream
     attribute @@toStringTag
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index cba8941..32ff4bf 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -532,7 +532,6 @@
 [Worker]     method createWritable
 [Worker]     method getFile
 [Worker]     method move
-[Worker]     method rename
 [Worker] interface FileSystemHandle
 [Worker]     attribute @@toStringTag
 [Worker]     getter kind
@@ -542,7 +541,6 @@
 [Worker]     method move
 [Worker]     method queryPermission
 [Worker]     method remove
-[Worker]     method rename
 [Worker]     method requestPermission
 [Worker] interface FileSystemSyncAccessHandle
 [Worker]     attribute @@toStringTag
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 0cc3d22..5bea641 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
@@ -2700,7 +2700,6 @@
     method createWritable
     method getFile
     method move
-    method rename
 interface FileSystemHandle
     attribute @@toStringTag
     getter kind
@@ -2710,7 +2709,6 @@
     method move
     method queryPermission
     method remove
-    method rename
     method requestPermission
 interface FileSystemWritableFileStream : WritableStream
     attribute @@toStringTag
@@ -11406,6 +11404,7 @@
     attribute propertyNamesInGlobal
     attribute testRunner
     attribute textInputController
+    getter anonymous
     getter appHistory
     getter attributionReporting
     getter caches
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index 63854ad..6011106 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -475,7 +475,6 @@
 [Worker]     method createWritable
 [Worker]     method getFile
 [Worker]     method move
-[Worker]     method rename
 [Worker] interface FileSystemHandle
 [Worker]     attribute @@toStringTag
 [Worker]     getter kind
@@ -485,7 +484,6 @@
 [Worker]     method move
 [Worker]     method queryPermission
 [Worker]     method remove
-[Worker]     method rename
 [Worker]     method requestPermission
 [Worker] interface FileSystemWritableFileStream : WritableStream
 [Worker]     attribute @@toStringTag
diff --git a/third_party/crc32c/OWNERS b/third_party/crc32c/OWNERS
index 06ed9aa..85a3dae 100644
--- a/third_party/crc32c/OWNERS
+++ b/third_party/crc32c/OWNERS
@@ -2,6 +2,5 @@
 pwnall@chromium.org
 
 # Secondary:
-cmumford@google.com
 jsbell@chromium.org
 mek@chromium.org
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn
index c46820fc..8974379c 100644
--- a/third_party/harfbuzz-ng/BUILD.gn
+++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -340,6 +340,10 @@
       defines += [ "HAVE_PTHREAD" ]
     }
 
+    if (is_mac) {
+      defines += [ "HAVE_XLOCALE_H" ]
+    }
+
     if (enable_paint_preview) {
       # Paint Previews make use of CFF subsetting. However, enabling this is
       # expensive for binary size so only compile it when Paint Previews are
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 35b5f56..8e2bc57 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,10 +1,10 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 3.1.2-41
-CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:3.1.2
-Date: 20211210
-Revision: 77507a1d8d872d8cd4f62b807e933cd3e2cdb110
+Version: 3.2.0-42
+CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:3.2.0
+Date: 20220112
+Revision: b8c2c1ab3778755a23ea449ba334959693388687
 Security Critical: yes
 License: MIT
 License File: src/COPYING
diff --git a/third_party/leveldatabase/OWNERS b/third_party/leveldatabase/OWNERS
index 06ed9aa..85a3dae 100644
--- a/third_party/leveldatabase/OWNERS
+++ b/third_party/leveldatabase/OWNERS
@@ -2,6 +2,5 @@
 pwnall@chromium.org
 
 # Secondary:
-cmumford@google.com
 jsbell@chromium.org
 mek@chromium.org
diff --git a/third_party/snappy/OWNERS b/third_party/snappy/OWNERS
index 9ada372..8de7804 100644
--- a/third_party/snappy/OWNERS
+++ b/third_party/snappy/OWNERS
@@ -2,6 +2,5 @@
 pwnall@chromium.org
 
 # Secondary
-cmumford@google.com
 jsbell@chromium.org
 mek@chromium.org
diff --git a/third_party/sqlite/OWNERS b/third_party/sqlite/OWNERS
index 14dfdc9e..9769549 100644
--- a/third_party/sqlite/OWNERS
+++ b/third_party/sqlite/OWNERS
@@ -2,5 +2,4 @@
 mek@chromium.org
 
 # Secondary:
-cmumford@google.com
 pwnall@chromium.org
diff --git a/third_party/zlib/google/test/data/README.md b/third_party/zlib/google/test/data/README.md
new file mode 100644
index 0000000..c76648fb
--- /dev/null
+++ b/third_party/zlib/google/test/data/README.md
@@ -0,0 +1,15 @@
+## test\_posix\_permissions.zip
+Rebuild this zip by running:
+```
+rm test_posix_permissions.zip &&
+mkdir z &&
+cd z &&
+touch 0.txt 1.txt 2.txt 3.txt &&
+chmod a+x 0.txt &&
+chmod o+x 1.txt &&
+chmod u+x 2.txt &&
+zip test_posix_permissions.zip * &&
+mv test_posix_permissions.zip .. &&
+cd .. &&
+rm -r z
+```
diff --git a/third_party/zlib/google/test/data/test_posix_permissions.zip b/third_party/zlib/google/test/data/test_posix_permissions.zip
new file mode 100644
index 0000000..a058ba1
--- /dev/null
+++ b/third_party/zlib/google/test/data/test_posix_permissions.zip
Binary files differ
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc
index 53fa13fd..f546a90d 100644
--- a/third_party/zlib/google/zip_reader.cc
+++ b/third_party/zlib/google/zip_reader.cc
@@ -24,6 +24,10 @@
 #endif  // defined(OS_WIN)
 #endif  // defined(USE_SYSTEM_MINIZIP)
 
+#if defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
 namespace zip {
 
 namespace {
@@ -52,6 +56,8 @@
 
   void SetTimeModified(const base::Time& time) override;
 
+  void SetPosixFilePermissions(int mode) override;
+
  private:
   size_t max_read_bytes_;
   std::string* output_;
@@ -81,6 +87,33 @@
   // Do nothing.
 }
 
+void StringWriterDelegate::SetPosixFilePermissions(int mode) {
+  // Do nothing.
+}
+
+#if defined(OS_POSIX)
+void SetPosixFilePermissions(int fd, int mode) {
+  base::stat_wrapper_t sb;
+  if (base::File::Fstat(fd, &sb)) {
+    return;
+  }
+  mode_t new_mode = sb.st_mode;
+  // Transfer the executable bit only if the file is readable.
+  if ((sb.st_mode & S_IRUSR) == S_IRUSR && (mode & S_IXUSR) == S_IXUSR) {
+    new_mode |= S_IXUSR;
+  }
+  if ((sb.st_mode & S_IRGRP) == S_IRGRP && (mode & S_IXGRP) == S_IXGRP) {
+    new_mode |= S_IXGRP;
+  }
+  if ((sb.st_mode & S_IROTH) == S_IROTH && (mode & S_IXOTH) == S_IXOTH) {
+    new_mode |= S_IXOTH;
+  }
+  if (new_mode != sb.st_mode) {
+    fchmod(fd, new_mode);
+  }
+}
+#endif
+
 }  // namespace
 
 // TODO(satorux): The implementation assumes that file names in zip files
@@ -91,7 +124,8 @@
     : file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)),
       is_directory_(false),
       is_unsafe_(false),
-      is_encrypted_(false) {
+      is_encrypted_(false),
+      posix_mode_(0) {
   original_size_ = raw_file_info.uncompressed_size;
 
   // Directory entries in zip files end with "/".
@@ -132,6 +166,11 @@
 
   if (!base::Time::FromUTCExploded(exploded_time, &last_modified_))
     last_modified_ = base::Time::UnixEpoch();
+
+#if defined(OS_POSIX)
+  posix_mode_ =
+      (raw_file_info.external_fa >> 16L) & (S_IRWXU | S_IRWXG | S_IRWXO);
+#endif
 }
 
 ZipReader::ZipReader() {
@@ -277,9 +316,11 @@
 
   unzCloseCurrentFile(zip_file_);
 
-  if (entire_file_extracted &&
-      current_entry_info()->last_modified() != base::Time::UnixEpoch()) {
-    delegate->SetTimeModified(current_entry_info()->last_modified());
+  if (entire_file_extracted) {
+    delegate->SetPosixFilePermissions(current_entry_info()->posix_mode());
+    if (current_entry_info()->last_modified() != base::Time::UnixEpoch()) {
+      delegate->SetTimeModified(current_entry_info()->last_modified());
+    }
   }
 
   return entire_file_extracted;
@@ -471,6 +512,12 @@
   file_->SetTimes(base::Time::Now(), time);
 }
 
+void FileWriterDelegate::SetPosixFilePermissions(int mode) {
+#if defined(OS_POSIX)
+  zip::SetPosixFilePermissions(file_->GetPlatformFile(), mode);
+#endif
+}
+
 // FilePathWriterDelegate ------------------------------------------------------
 
 FilePathWriterDelegate::FilePathWriterDelegate(
@@ -499,4 +546,10 @@
   base::TouchFile(output_file_path_, base::Time::Now(), time);
 }
 
+void FilePathWriterDelegate::SetPosixFilePermissions(int mode) {
+#if defined(OS_POSIX)
+  zip::SetPosixFilePermissions(file_.GetPlatformFile(), mode);
+#endif
+}
+
 }  // namespace zip
diff --git a/third_party/zlib/google/zip_reader.h b/third_party/zlib/google/zip_reader.h
index e1ca7aa4..c2d3bea8 100644
--- a/third_party/zlib/google/zip_reader.h
+++ b/third_party/zlib/google/zip_reader.h
@@ -41,6 +41,11 @@
 
   // Sets the last-modified time of the data.
   virtual void SetTimeModified(const base::Time& time) = 0;
+
+  // Called with the POSIX file permissions of the data; POSIX implementations
+  // may apply some of the permissions (for example, the executable bit) to the
+  // output file.
+  virtual void SetPosixFilePermissions(int mode) = 0;
 };
 
 // This class is used for reading zip files. A typical use case of this
@@ -112,6 +117,9 @@
     // Returns true if the entry is encrypted.
     bool is_encrypted() const { return is_encrypted_; }
 
+    // Returns the posix file permissions of the entry.
+    int posix_mode() const { return posix_mode_; }
+
    private:
     const base::FilePath file_path_;
     int64_t original_size_;
@@ -119,6 +127,7 @@
     bool is_directory_;
     bool is_unsafe_;
     bool is_encrypted_;
+    int posix_mode_;
   };
 
   ZipReader();
@@ -261,6 +270,10 @@
   // Sets the last-modified time of the data.
   void SetTimeModified(const base::Time& time) override;
 
+  // On POSIX systems, sets the file to be executable if the source file was
+  // executable.
+  void SetPosixFilePermissions(int mode) override;
+
   // Return the actual size of the file.
   int64_t file_length() { return file_length_; }
 
@@ -297,6 +310,10 @@
   // Sets the last-modified time of the data.
   void SetTimeModified(const base::Time& time) override;
 
+  // On POSIX systems, sets the file to be executable if the source file was
+  // executable.
+  void SetPosixFilePermissions(int mode) override;
+
  private:
   base::FilePath output_file_path_;
   base::File file_;
diff --git a/third_party/zlib/google/zip_reader_unittest.cc b/third_party/zlib/google/zip_reader_unittest.cc
index c1d654af..a15193b4 100644
--- a/third_party/zlib/google/zip_reader_unittest.cc
+++ b/third_party/zlib/google/zip_reader_unittest.cc
@@ -23,8 +23,10 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -111,6 +113,7 @@
   MOCK_METHOD0(PrepareOutput, bool());
   MOCK_METHOD2(WriteBytes, bool(const char*, int));
   MOCK_METHOD1(SetTimeModified, void(const base::Time&));
+  MOCK_METHOD1(SetPosixFilePermissions, void(int));
 };
 
 bool ExtractCurrentEntryToFilePath(zip::ZipReader* reader,
@@ -564,6 +567,38 @@
   reader.Close();
 }
 
+TEST_F(ZipReaderTest, ExtractPosixPermissions) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  ZipReader reader;
+  ASSERT_TRUE(
+      reader.Open(test_data_dir_.AppendASCII("test_posix_permissions.zip")));
+  for (auto entry : {"0.txt", "1.txt", "2.txt", "3.txt"}) {
+    ASSERT_TRUE(LocateAndOpenEntry(&reader, base::FilePath::FromASCII(entry)));
+    FilePathWriterDelegate delegate(temp_dir.GetPath().AppendASCII(entry));
+    ASSERT_TRUE(reader.ExtractCurrentEntry(&delegate, 10000));
+  }
+  reader.Close();
+
+#if defined(OS_POSIX)
+  // This assumes a umask of at least 0400.
+  int mode = 0;
+  EXPECT_TRUE(base::GetPosixFilePermissions(
+      temp_dir.GetPath().AppendASCII("0.txt"), &mode));
+  EXPECT_EQ(mode & 0700, 0700);
+  EXPECT_TRUE(base::GetPosixFilePermissions(
+      temp_dir.GetPath().AppendASCII("1.txt"), &mode));
+  EXPECT_EQ(mode & 0700, 0600);
+  EXPECT_TRUE(base::GetPosixFilePermissions(
+      temp_dir.GetPath().AppendASCII("2.txt"), &mode));
+  EXPECT_EQ(mode & 0700, 0700);
+  EXPECT_TRUE(base::GetPosixFilePermissions(
+      temp_dir.GetPath().AppendASCII("3.txt"), &mode));
+  EXPECT_EQ(mode & 0700, 0600);
+#endif
+}
+
 // This test exposes http://crbug.com/430959, at least on OS X
 TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) {
   for (int i = 0; i < 100000; ++i) {
@@ -617,6 +652,7 @@
       .WillOnce(Return(true));
   EXPECT_CALL(mock_writer, WriteBytes(_, _))
       .WillRepeatedly(Return(true));
+  EXPECT_CALL(mock_writer, SetPosixFilePermissions(_));
   EXPECT_CALL(mock_writer, SetTimeModified(_));
 
   base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index 392b16c..5f2d63e 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -563,8 +563,7 @@
   return ret
 
 
-def _UpdateSymbolNamesFromNm(raw_symbols, names_by_address):
-  """Updates raw_symbols names with extra information from nm."""
+def _AddOutlinedSymbolCountsFromNm(raw_symbols, names_by_address):
   logging.debug('Update symbol names')
   # linker_map_parser extracts '** outlined function' without knowing how many
   # such symbols exist at each address. nm has this information, and stores the
@@ -927,7 +926,10 @@
         'Adding symbols removed by identical code folding (as reported by nm)')
     # This normally does not block (it's finished by this time).
     names_by_address = elf_nm_result.get()
-    _UpdateSymbolNamesFromNm(raw_symbols, names_by_address)
+    if native_spec.map_path:
+      # This rewrites outlined symbols from |map_path|, and can be skipped if
+      # symbols already came from nm (e.g., for dwarf mode).
+      _AddOutlinedSymbolCountsFromNm(raw_symbols, names_by_address)
 
     raw_symbols = _AddNmAliases(raw_symbols, names_by_address)
 
@@ -2179,6 +2181,10 @@
   # Iterate over each container.
   for (sub_args, apk_spec, pak_spec, native_specs, container_name,
        resources_pathmap_path) in _IterSubArgs(top_args, on_config_error):
+    # TODO(https://crbug.com/1286642): Re-enable dwarf mode specs.
+    if apk_spec:
+      native_specs = [s for s in native_specs if s.algorithm != 'dwarf']
+
     if not native_specs:
       native_specs = [None]
 
diff --git a/tools/metrics/histograms/metadata/bluetooth/histograms.xml b/tools/metrics/histograms/metadata/bluetooth/histograms.xml
index bdc36948..e11713d 100644
--- a/tools/metrics/histograms/metadata/bluetooth/histograms.xml
+++ b/tools/metrics/histograms/metadata/bluetooth/histograms.xml
@@ -317,6 +317,18 @@
   </token>
 </histogram>
 
+<histogram name="Bluetooth.ChromeOS.FastPair.ConfirmPasskey.Latency" units="ms"
+    expires_after="2022-09-20">
+  <owner>shanefitz@google.com</owner>
+  <owner>julietlevesque@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records the total time it takes after being asked to confirm a passkey from
+    the device for the Chromebook to confirm the passkey. Emitted on a
+    successful confirmation of the passkey. No metric is emitted on failure.
+  </summary>
+</histogram>
+
 <histogram name="Bluetooth.ChromeOS.FastPair.ConnectDevice.Result"
     enum="BooleanSuccess" expires_after="2022-09-20">
   <owner>shanefitz@google.com</owner>
@@ -846,6 +858,21 @@
   </summary>
 </histogram>
 
+<histogram name="Bluetooth.ChromeOS.FastPair.RequestPasskey.Latency" units="ms"
+    expires_after="2022-09-20">
+  <owner>shanefitz@google.com</owner>
+  <owner>julietlevesque@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    Records the total time it takes after connecting to the device following the
+    secret key exchange for the Chromebook to be asked by the device to confirm
+    the passkey. Emitted during the pairing protocol when the BluetoothDevice
+    pairing delegate is prompted to confirm the passkey. This metric is only
+    emitted to following a successful connection to the device, not emitted on
+    failure.
+  </summary>
+</histogram>
+
 <histogram name="Bluetooth.ChromeOS.FastPair.RetroactiveEngagementFunnel.Steps"
     enum="FastPairRetroactiveEngagementFlowEvent" expires_after="2022-09-20">
   <owner>shanefitz@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/cookie/histograms.xml b/tools/metrics/histograms/metadata/cookie/histograms.xml
index 986a957..5e1fd15 100644
--- a/tools/metrics/histograms/metadata/cookie/histograms.xml
+++ b/tools/metrics/histograms/metadata/cookie/histograms.xml
@@ -1025,6 +1025,9 @@
 
 <histogram name="Cookie.TimeDatabaseMigrationToV14" units="ms"
     expires_after="2022-01-09">
+  <obsolete>
+    Removed Jan 2022: no longer needed and expired.
+  </obsolete>
   <owner>wfh@chromium.org</owner>
   <owner>bingler@chromium.org</owner>
   <owner>morlovich@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index 01422397..30a8756 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -2321,7 +2321,7 @@
 </histogram>
 
 <histogram name="EventLatency.TotalLatency" units="microseconds"
-    expires_after="2022-06-26">
+    expires_after="2023-01-16">
   <owner>mohsen@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -2334,7 +2334,7 @@
 </histogram>
 
 <histogram name="EventLatency.{EventType}.{Breakdown}" units="microseconds"
-    expires_after="2022-01-16">
+    expires_after="2023-01-16">
   <owner>mohsen@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -2347,7 +2347,7 @@
 </histogram>
 
 <histogram name="EventLatency.{PinchEventType}.{PinchInputType}.{Breakdown}"
-    units="microseconds" expires_after="2022-01-16">
+    units="microseconds" expires_after="2023-01-16">
   <owner>mohsen@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -2361,7 +2361,7 @@
 </histogram>
 
 <histogram name="EventLatency.{ScrollEventType}.{ScrollInputType}.{Breakdown}"
-    units="microseconds" expires_after="2022-01-16">
+    units="microseconds" expires_after="2023-01-16">
   <owner>mohsen@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/memory/histograms.xml b/tools/metrics/histograms/metadata/memory/histograms.xml
index 6f59e134..bc45b82a 100644
--- a/tools/metrics/histograms/metadata/memory/histograms.xml
+++ b/tools/metrics/histograms/metadata/memory/histograms.xml
@@ -2384,7 +2384,7 @@
 </histogram>
 
 <histogram name="Memory.PartitionAlloc.ThreadCache.BatchFillRate{ThreadType}"
-    units="%" expires_after="M97">
+    units="%" expires_after="M102">
   <owner>lizeb@chromium.org</owner>
   <owner>bartekn@chromium.org</owner>
   <summary>
@@ -2400,7 +2400,7 @@
 </histogram>
 
 <histogram name="Memory.PartitionAlloc.ThreadCache.HitRate{ThreadType}"
-    units="%" expires_after="M97">
+    units="%" expires_after="M102">
   <owner>lizeb@chromium.org</owner>
   <owner>bartekn@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml
index c38b1d2..63a85606 100644
--- a/tools/metrics/histograms/metadata/power/histograms.xml
+++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -1067,6 +1067,9 @@
 
 <histogram name="Power.Mac.AppleSMCOpened" enum="BooleanSuccess"
     expires_after="2022-07-03">
+  <obsolete>
+    Stopped reporting in M98, deprecated in M99
+  </obsolete>
   <owner>lgrey@chromium.org</owner>
   <summary>
     When metrics collection started, records true if a handle to the System
diff --git a/tools/metrics/histograms/print_histogram_names.py b/tools/metrics/histograms/print_histogram_names.py
index 712dea8b..8ac4b8c1 100755
--- a/tools/metrics/histograms/print_histogram_names.py
+++ b/tools/metrics/histograms/print_histogram_names.py
@@ -107,7 +107,8 @@
   if args.diff is not None:
     print_diff_names(args.diff)
   else:
-    for name in get_names(histogram_xml_files()):
+    name_set, _ = get_names(histogram_xml_files())
+    for name in sorted(list(name_set)):
       print(name)
 
 
diff --git a/tools/perfbot-analysis/bulk-download.js b/tools/perfbot-analysis/bulk-download.js
index 2d260d55..b12d3da0 100644
--- a/tools/perfbot-analysis/bulk-download.js
+++ b/tools/perfbot-analysis/bulk-download.js
@@ -4,19 +4,12 @@
 
 'use strict';
 
-function tryRequire(name) {
-  try {
-    return require(name);
-  } catch (ex) {
-    return undefined;
-  }
-}
-
 const bulider = require('./builder.js');
 const gsutil = require('./gsutil.js');
+const tryrequire = require('./try-require.js');
 
 const fs = require('fs');
-const yargs = tryRequire('yargs');
+const yargs = tryrequire.tryrequire('yargs');
 if (!yargs) {
   console.error('Please install the `yargs` package from npm (`npm i yargs`).');
   return;
@@ -75,32 +68,40 @@
   printUpdate(`Found ${children.length} child tasks.`);
 
   const all = {};
+  const promises = [];
+  let taskno = 0;
   for (const child of children) {
-    const output = child.downloadJSONFile('output.json');
+    const p = child.downloadJSONFile('output.json');
+    promises.push(p);
 
-    if (argv.benchmark in output.tests) {
-      const tests = Object.keys(output.tests[argv.benchmark]);
-      printUpdate(`${tests.length} tests found for ${argv.benchmark} in ${
-          child.task_id}.`);
-      for (const t of tests) {
-        const artifacts = output.tests[argv.benchmark][t].artifacts;
-        if (artifacts && artifacts['trace.html']) {
-          const trace = artifacts['trace.html'];
-          const url =
-              (typeof (trace) === 'object' && typeof (trace[0]) === 'string') ?
-              trace[0] :
-              trace;
-          if (t in all) {
-            all[t].push(url);
-          } else {
-            all[t] = [url];
+    p.then((output) => {
+      if (argv.benchmark in output.tests) {
+        const tests = Object.keys(output.tests[argv.benchmark]);
+        printUpdate(
+            `${++taskno}/${children.length} ${tests.length} tests found for ${
+                argv.benchmark} in ${child.task_id}.`);
+        for (const t of tests) {
+          const artifacts = output.tests[argv.benchmark][t].artifacts;
+          if (artifacts && artifacts['trace.html']) {
+            const trace = artifacts['trace.html'];
+            const url = (typeof (trace) === 'object' &&
+                         typeof (trace[0]) === 'string') ?
+                trace[0] :
+                trace;
+            if (t in all) {
+              all[t].push(url);
+            } else {
+              all[t] = [url];
+            }
           }
         }
+      } else {
+        printUpdate(`${++taskno}/${children.length} 0 tests found for ${
+            argv.benchmark} in ${child.task_id}.`);
       }
-    } else {
-      printUpdate(`0 tests found for ${argv.benchmark} in ${child.task_id}.`);
-    }
+    });
   }
+  await Promise.all(promises);
 
   // Maps a gs:// url to a local filename.
   const map = {};
diff --git a/tools/perfbot-analysis/gsutil.js b/tools/perfbot-analysis/gsutil.js
index 53e4897..f3a9e773 100644
--- a/tools/perfbot-analysis/gsutil.js
+++ b/tools/perfbot-analysis/gsutil.js
@@ -19,10 +19,11 @@
 
 // Downloads a list of files.
 // `map` is a map of {<gs:// url> : <local-filename>}.
-// `output`is the local directory to download the files to.
+// `output` is the local directory to download the files to.
 async function downloadFiles(map, output) {
   let downloaded = 0;
   const total = Object.keys(map).length;
+  process.stdout.write(`\r*** ${downloaded}/${total} files downloaded.`);
   function exec(cmd, options) {
     return new Promise((resolve, reject) => {
       child_process.exec(cmd, options, () => {
diff --git a/tools/perfbot-analysis/query-runner.js b/tools/perfbot-analysis/query-runner.js
index 7fce0e6..6169f27 100644
--- a/tools/perfbot-analysis/query-runner.js
+++ b/tools/perfbot-analysis/query-runner.js
@@ -29,8 +29,8 @@
     return JSON.parse(output.toString());
   }
 
-  // Returns a parsed JSON object from the contents in `filename` for the
-  // specified `task_id`.
+  // Returns a promoise for a parsed JSON object from the contents in `filename`
+  // for the specified `task_id`.
   retrieveJSONFile(task_id, filename) {
     // This is going to create some temp directory. So put this in a try/finally
     // block so that the temp directory gets cleaned up correctly.
@@ -53,13 +53,16 @@
   }
 
   retrieveFile_(task_id, filename, temp_dir) {
-    const cmds = [
-      this.bin_, 'collect', '-S', this.swarming_server_,
-      `-output-dir="${temp_dir}"`, task_id
-    ];
-    const output = child_process.execSync(cmds.join(' '));
-    const filepath = path.join(temp_dir, task_id, filename);
-    return JSON.parse(fs.readFileSync(filepath).toString());
+    return new Promise((resolve, reject) => {
+      const cmds = [
+        this.bin_, 'collect', '-S', this.swarming_server_,
+        `-output-dir="${temp_dir}"`, task_id
+      ];
+      const output = child_process.exec(cmds.join(' '), () => {
+        const filepath = path.join(temp_dir, task_id, filename);
+        resolve(JSON.parse(fs.readFileSync(filepath).toString()));
+      });
+    });
   }
 };
 
diff --git a/tools/perfbot-analysis/swarming-task.js b/tools/perfbot-analysis/swarming-task.js
index ca0dee9..a753b6f 100644
--- a/tools/perfbot-analysis/swarming-task.js
+++ b/tools/perfbot-analysis/swarming-task.js
@@ -31,7 +31,9 @@
 // artifacts. So to find all the failed tests, it downloads the artifacts from
 // the swarming server, and parses the `output.json` file.
 class ChildSwarmingTask extends SwarmingTask {
-  downloadJSONFile(filename) {
+  // Returns a promoise for a parsed JSON object from the contents in
+  // `filename` for this task.
+  async downloadJSONFile(filename) {
     return this.query_runner_.retrieveJSONFile(this.task_id_, filename);
   }
 };
diff --git a/tools/perfbot-analysis/try-require.js b/tools/perfbot-analysis/try-require.js
new file mode 100644
index 0000000..eb6b1a0
--- /dev/null
+++ b/tools/perfbot-analysis/try-require.js
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+function tryrequire(name) {
+  try {
+    return require(name);
+  } catch (x) {
+    return undefined;
+  }
+}
+
+module.exports = {
+  tryrequire,
+}
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index a731210f..08eccae 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -131,6 +131,12 @@
   return nullptr;
 }
 
+AXPlatformNodeBase* AXPlatformNodeBase::GetPlatformParent() const {
+  if (delegate_)
+    return FromNativeViewAccessible(delegate_->GetParent());
+  return nullptr;
+}
+
 int AXPlatformNodeBase::GetChildCount() const {
   if (delegate_)
     return delegate_->GetChildCount();
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index 3ad7323..a536a2b 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -102,6 +102,7 @@
   bool IsDescendantOf(AXPlatformNode* ancestor) const override;
 
   // Helpers.
+  AXPlatformNodeBase* GetPlatformParent() const;
   AXPlatformNodeBase* GetPreviousSibling() const;
   AXPlatformNodeBase* GetNextSibling() const;
   AXPlatformNodeBase* GetFirstChild() const;
diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm
index 54f1f8d1..e3e0d94a 100644
--- a/ui/accessibility/platform/ax_platform_node_cocoa.mm
+++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm
@@ -12,6 +12,7 @@
 #include "base/trace_event/trace_event.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_role_properties.h"
 #include "ui/accessibility/platform/ax_platform_node_mac.h"
 #include "ui/accessibility/platform/ax_private_attributes_mac.h"
 #include "ui/accessibility/platform/ax_private_roles_mac.h"
@@ -653,6 +654,7 @@
 
   // These attributes are required on all accessibility objects.
   NSArray* const kAllRoleAttributes = @[
+    NSAccessibilityBlockQuoteLevelAttribute,
     NSAccessibilityDOMClassList,
     NSAccessibilityDOMIdentifierAttribute,
     NSAccessibilityChildrenAttribute,
@@ -1005,6 +1007,24 @@
   return [self getStringAttribute:ax::mojom::StringAttribute::kAutoComplete];
 }
 
+- (id)AXBlockQuoteLevel {
+  if (![self instanceActive])
+    return nil;
+  // This is for the number of ancestors that are a <blockquote>, including
+  // self, useful for tracking replies to replies etc. in an email.
+  int level = 0;
+
+  for (ui::AXPlatformNodeBase* ancestor = _node; ancestor;
+       ancestor = ancestor->GetPlatformParent()) {
+    // Do not cross document boundaries.
+    if (ui::IsPlatformDocument(ancestor->GetRole()))
+      break;
+    if (ancestor->GetRole() == ax::mojom::Role::kBlockquote)
+      ++level;
+  }
+  return @(level);
+}
+
 - (NSArray*)AXColumnHeaderUIElements {
   return [self accessibilityColumnHeaderUIElements];
 }
diff --git a/ui/accessibility/platform/ax_private_attributes_mac.h b/ui/accessibility/platform/ax_private_attributes_mac.h
index 30b59fb1..bf19e99 100644
--- a/ui/accessibility/platform/ax_private_attributes_mac.h
+++ b/ui/accessibility/platform/ax_private_attributes_mac.h
@@ -36,6 +36,8 @@
     @"AXARIASetSize";
 AX_EXPORT constexpr NSString* const NSAccessibilityAutocompleteValueAttribute =
     @"AXAutocompleteValue";
+AX_EXPORT constexpr NSString* const NSAccessibilityBlockQuoteLevelAttribute =
+    @"AXBlockQuoteLevel";
 AX_EXPORT constexpr NSString* const NSAccessibilityDetailsElementsAttribute =
     @"AXDetailsElements";
 AX_EXPORT constexpr NSString* const NSAccessibilityDOMClassList =
diff --git a/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm b/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm
index 70ea63c..94f9c50 100644
--- a/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm
+++ b/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm
@@ -47,6 +47,7 @@
        NSAccessibilityARIARowIndexAttribute,
        NSAccessibilityARIASetSizeAttribute,
        NSAccessibilityAutocompleteValueAttribute,
+       NSAccessibilityBlockQuoteLevelAttribute,
        NSAccessibilityColumnHeaderUIElementsAttribute,
        NSAccessibilityDetailsElementsAttribute,
        NSAccessibilityDOMClassList,
diff --git a/ui/aura/test/test_screen.cc b/ui/aura/test/test_screen.cc
index 21c1e8b..c5a60a65 100644
--- a/ui/aura/test/test_screen.cc
+++ b/ui/aura/test/test_screen.cc
@@ -74,7 +74,7 @@
   display::Display display(GetPrimaryDisplay());
   gfx::DisplayColorSpaces display_color_spaces(color_space,
                                                gfx::BufferFormat::RGBA_8888);
-  display_color_spaces.SetSDRWhiteLevel(sdr_white_level);
+  display_color_spaces.SetSDRMaxLuminanceNits(sdr_white_level);
   display.set_color_spaces(display_color_spaces);
   display_list().UpdateDisplay(display);
 }
diff --git a/ui/compositor/compositor_unittest.cc b/ui/compositor/compositor_unittest.cc
index e2f42f7..1f98b00 100644
--- a/ui/compositor/compositor_unittest.cc
+++ b/ui/compositor/compositor_unittest.cc
@@ -204,7 +204,7 @@
   color_matrix.set(2, 2, 0.4f);
   gfx::DisplayColorSpaces display_color_spaces(
       gfx::ColorSpace::CreateDisplayP3D65());
-  display_color_spaces.SetSDRWhiteLevel(1.f);
+  display_color_spaces.SetSDRMaxLuminanceNits(1.f);
   base::TimeTicks vsync_timebase(base::TimeTicks::Now());
   base::TimeDelta vsync_interval(base::Milliseconds(250));
   compositor()->SetDisplayColorMatrix(color_matrix);
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h
index 12a99f4..d8265bb 100644
--- a/ui/compositor/test/in_process_context_factory.h
+++ b/ui/compositor/test/in_process_context_factory.h
@@ -79,7 +79,6 @@
 
   skia::Matrix44 GetOutputColorMatrix(Compositor* compositor) const;
   gfx::DisplayColorSpaces GetDisplayColorSpaces(Compositor* compositor) const;
-  float GetSDRWhiteLevel(Compositor* compositor) const;
   base::TimeTicks GetDisplayVSyncTimeBase(Compositor* compositor) const;
   base::TimeDelta GetDisplayVSyncTimeInterval(Compositor* compositor) const;
   void ResetDisplayOutputParameters(Compositor* compositor);
diff --git a/ui/display/manager/display_change_observer.cc b/ui/display/manager/display_change_observer.cc
index cc411b2d..26fe525 100644
--- a/ui/display/manager/display_change_observer.cc
+++ b/ui/display/manager/display_change_observer.cc
@@ -129,7 +129,8 @@
         gfx::ContentColorUsage::kHDR, true /* needs_alpha */, hdr_color_space,
         gfx::BufferFormat::RGBA_1010102);
 
-    display_color_spaces.set_hdr_static_metadata(hdr_static_metadata);
+    // TODO(https://crbug.com/1286074): Populate maximum luminance based on
+    // `hdr_static_metadata`.
   }
   return display_color_spaces;
 }
diff --git a/ui/display/win/screen_win.cc b/ui/display/win/screen_win.cc
index d8404fd..690e74d 100644
--- a/ui/display/win/screen_win.cc
+++ b/ui/display/win/screen_win.cc
@@ -213,7 +213,7 @@
   // https://crbug.com/1057163).
   display_color_spaces.SetOutputBufferFormats(gfx::BufferFormat::BGRX_8888,
                                               gfx::BufferFormat::BGRA_8888);
-  display_color_spaces.SetSDRWhiteLevel(sdr_white_level);
+  display_color_spaces.SetSDRMaxLuminanceNits(sdr_white_level);
   return display_color_spaces;
 }
 
diff --git a/ui/gfx/display_color_spaces.cc b/ui/gfx/display_color_spaces.cc
index a5b8e14..51758f0 100644
--- a/ui/gfx/display_color_spaces.cc
+++ b/ui/gfx/display_color_spaces.cc
@@ -189,7 +189,9 @@
     if (buffer_formats_[i] != other.buffer_formats_[i])
       return false;
   }
-  if (sdr_white_level_ != other.sdr_white_level_)
+  if (sdr_max_luminance_nits_ != other.sdr_max_luminance_nits_)
+    return false;
+  if (hdr_max_luminance_relative_ != other.hdr_max_luminance_relative_)
     return false;
 
   return true;
diff --git a/ui/gfx/display_color_spaces.h b/ui/gfx/display_color_spaces.h
index 85d3d8e8..7a7fbd7 100644
--- a/ui/gfx/display_color_spaces.h
+++ b/ui/gfx/display_color_spaces.h
@@ -77,19 +77,21 @@
   BufferFormat GetOutputBufferFormat(ContentColorUsage color_usage,
                                      bool needs_alpha) const;
 
-  // Set the custom SDR white level, in nits. This is a non-default value only
+  // Set the maximum SDR luminance, in nits. This is a non-default value only
   // on Windows.
-  void SetSDRWhiteLevel(float sdr_white_level) {
-    sdr_white_level_ = sdr_white_level;
+  void SetSDRMaxLuminanceNits(float sdr_max_luminance_nits) {
+    sdr_max_luminance_nits_ = sdr_max_luminance_nits;
   }
-  float GetSDRWhiteLevel() const { return sdr_white_level_; }
+  float GetSDRMaxLuminanceNits() const { return sdr_max_luminance_nits_; }
 
-  void set_hdr_static_metadata(
-      absl::optional<HDRStaticMetadata> hdr_static_metadata) {
-    hdr_static_metadata_ = hdr_static_metadata;
+  // Set the maximum luminance that HDR content can display. This is represented
+  // as a multiple of the SDR white luminance (so a display that is incapable of
+  // HDR would have a value of 1.0).
+  void SetHDRMaxLuminanceRelative(float hdr_max_luminance_relative) {
+    hdr_max_luminance_relative_ = hdr_max_luminance_relative;
   }
-  const absl::optional<HDRStaticMetadata>& hdr_static_metadata() const {
-    return hdr_static_metadata_;
+  float GetHDRMaxLuminanceRelative() const {
+    return hdr_max_luminance_relative_;
   }
 
   // TODO(https://crbug.com/1116870): These helper functions exist temporarily
@@ -128,9 +130,8 @@
 
   gfx::ColorSpace color_spaces_[kConfigCount];
   gfx::BufferFormat buffer_formats_[kConfigCount];
-  float sdr_white_level_ = ColorSpace::kDefaultSDRWhiteLevel;
-  // By definition this only applies to ContentColorUsage::kHDR.
-  absl::optional<HDRStaticMetadata> hdr_static_metadata_;
+  float sdr_max_luminance_nits_ = ColorSpace::kDefaultSDRWhiteLevel;
+  float hdr_max_luminance_relative_ = 1.f;
 };
 
 }  // namespace gfx
diff --git a/ui/gfx/ipc/color/gfx_param_traits.cc b/ui/gfx/ipc/color/gfx_param_traits.cc
index 2e9b2b5..108b9571 100644
--- a/ui/gfx/ipc/color/gfx_param_traits.cc
+++ b/ui/gfx/ipc/color/gfx_param_traits.cc
@@ -51,7 +51,8 @@
     const gfx::DisplayColorSpaces& p) {
   WriteParam(m, p.color_spaces_);
   WriteParam(m, p.buffer_formats_);
-  WriteParam(m, p.sdr_white_level_);
+  WriteParam(m, p.sdr_max_luminance_nits_);
+  WriteParam(m, p.hdr_max_luminance_relative_);
 }
 
 bool ParamTraits<gfx::DisplayColorSpaces>::Read(const base::Pickle* m,
@@ -61,7 +62,9 @@
     return false;
   if (!ReadParam(m, iter, &r->buffer_formats_))
     return false;
-  if (!ReadParam(m, iter, &r->sdr_white_level_))
+  if (!ReadParam(m, iter, &r->sdr_max_luminance_nits_))
+    return false;
+  if (!ReadParam(m, iter, &r->hdr_max_luminance_relative_))
     return false;
   return true;
 }
diff --git a/ui/gfx/mojom/display_color_spaces.mojom b/ui/gfx/mojom/display_color_spaces.mojom
index 900e43e..f22f2f8 100644
--- a/ui/gfx/mojom/display_color_spaces.mojom
+++ b/ui/gfx/mojom/display_color_spaces.mojom
@@ -24,8 +24,9 @@
   array<ColorSpace, 6> color_spaces;
   array<BufferFormat, 6> buffer_formats;
 
-  // The SDR white level is used to composite SDR and HDR content on Windows.
-  float sdr_white_level;
+  // The maximum SDR luminance, in nits.
+  float sdr_max_luminance_nits;
 
-  gfx.mojom.HDRStaticMetadata? hdr_static_metadata;
+  // The maximum HDR luminance, as a multiple of the SDR maximum luminance.
+  float hdr_max_luminance_relative;
 };
diff --git a/ui/gfx/mojom/display_color_spaces_mojom_traits.cc b/ui/gfx/mojom/display_color_spaces_mojom_traits.cc
index 1077123..773b967 100644
--- a/ui/gfx/mojom/display_color_spaces_mojom_traits.cc
+++ b/ui/gfx/mojom/display_color_spaces_mojom_traits.cc
@@ -68,12 +68,8 @@
   if (!input.ReadColorSpaces(&color_spaces))
     return false;
 
-  out->SetSDRWhiteLevel(input.sdr_white_level());
-
-  absl::optional<gfx::HDRStaticMetadata> hdr_static_metadata(
-      out->hdr_static_metadata_);
-  if (!input.ReadHdrStaticMetadata(&hdr_static_metadata))
-    return false;
+  out->SetSDRMaxLuminanceNits(input.sdr_max_luminance_nits());
+  out->SetHDRMaxLuminanceRelative(input.hdr_max_luminance_relative());
 
   return true;
 }
diff --git a/ui/gfx/mojom/display_color_spaces_mojom_traits.h b/ui/gfx/mojom/display_color_spaces_mojom_traits.h
index 8a69547..f218253 100644
--- a/ui/gfx/mojom/display_color_spaces_mojom_traits.h
+++ b/ui/gfx/mojom/display_color_spaces_mojom_traits.h
@@ -30,14 +30,13 @@
       const gfx::DisplayColorSpaces& input);
   static base::span<const gfx::BufferFormat> buffer_formats(
       const gfx::DisplayColorSpaces& input);
-  static float sdr_white_level(const gfx::DisplayColorSpaces& input) {
-    return input.GetSDRWhiteLevel();
+  static float sdr_max_luminance_nits(const gfx::DisplayColorSpaces& input) {
+    return input.GetSDRMaxLuminanceNits();
   }
-  static const absl::optional<gfx::HDRStaticMetadata>& hdr_static_metadata(
+  static float hdr_max_luminance_relative(
       const gfx::DisplayColorSpaces& input) {
-    return input.hdr_static_metadata();
+    return input.GetHDRMaxLuminanceRelative();
   }
-
   static bool Read(gfx::mojom::DisplayColorSpacesDataView data,
                    gfx::DisplayColorSpaces* out);
 };
diff --git a/ui/views/color_chooser/color_chooser_view.cc b/ui/views/color_chooser/color_chooser_view.cc
index 7df7beac..86a3a7d 100644
--- a/ui/views/color_chooser/color_chooser_view.cc
+++ b/ui/views/color_chooser/color_chooser_view.cc
@@ -39,7 +39,6 @@
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/grid_layout.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
@@ -434,23 +433,18 @@
   view->AddChildView(std::move(container));
 
   auto container2 = std::make_unique<View>();
-  GridLayout* layout =
-      container2->SetLayoutManager(std::make_unique<views::GridLayout>());
-  ColumnSet* columns = layout->AddColumnSet(0);
-  columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
-                     GridLayout::ColumnSize::kUsePreferred, 0, 0);
-  columns->AddPaddingColumn(0, kMarginWidth);
-  columns->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
-                     GridLayout::ColumnSize::kUsePreferred, 0, 0);
-  layout->StartRow(0, 0);
+  BoxLayout* layout =
+      container2->SetLayoutManager(std::make_unique<views::BoxLayout>(
+          BoxLayout::Orientation::kHorizontal, gfx::Insets(), kMarginWidth));
   auto textfield = std::make_unique<Textfield>();
   textfield->set_controller(this);
   textfield->SetDefaultWidthInChars(kTextfieldLengthInChars);
   textfield->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_COLOR_CHOOSER_HEX_INPUT));
-  textfield_ = layout->AddView(std::move(textfield));
+  textfield_ = container2->AddChildView(std::move(textfield));
   selected_color_patch_ =
-      layout->AddView(std::make_unique<SelectedColorPatchView>());
+      container2->AddChildView(std::make_unique<SelectedColorPatchView>());
+  layout->SetFlexForView(selected_color_patch_, 1);
   view->AddChildView(std::move(container2));
 
   OnColorChanged(initial_color_);
diff --git a/ui/views/examples/BUILD.gn b/ui/views/examples/BUILD.gn
index d2f7a56b..48bffcc1 100644
--- a/ui/views/examples/BUILD.gn
+++ b/ui/views/examples/BUILD.gn
@@ -98,6 +98,13 @@
     "widget_example.h",
   ]
 
+  if (is_linux || is_chromeos || is_fuchsia) {
+    sources += [
+      "color_chooser_example.cc",
+      "color_chooser_example.h",
+    ]
+  }
+
   defines = [
     "GFX_VECTOR_ICONS_UNSAFE",
     "VIEWS_EXAMPLES_IMPLEMENTATION",
diff --git a/ui/views/examples/color_chooser_example.cc b/ui/views/examples/color_chooser_example.cc
new file mode 100644
index 0000000..8325ca1c
--- /dev/null
+++ b/ui/views/examples/color_chooser_example.cc
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/examples/color_chooser_example.h"
+
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views::examples {
+
+ColorChooserExample::ColorChooserExample() : ExampleBase("ColorChooser") {}
+
+ColorChooserExample::~ColorChooserExample() = default;
+
+void ColorChooserExample::CreateExampleView(View* container) {
+  container->SetUseDefaultFillLayout(true);
+  container->AddChildView(
+      chooser_.MakeWidgetDelegate()->TransferOwnershipOfContentsView());
+}
+
+void ColorChooserExample::OnColorChosen(SkColor color) {}
+
+void ColorChooserExample::OnColorChooserDialogClosed() {}
+
+}  // namespace views::examples
diff --git a/ui/views/examples/color_chooser_example.h b/ui/views/examples/color_chooser_example.h
new file mode 100644
index 0000000..b5f4ba0
--- /dev/null
+++ b/ui/views/examples/color_chooser_example.h
@@ -0,0 +1,39 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_EXAMPLES_COLOR_CHOOSER_EXAMPLE_H_
+#define UI_VIEWS_EXAMPLES_COLOR_CHOOSER_EXAMPLE_H_
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/views/color_chooser/color_chooser_listener.h"
+#include "ui/views/color_chooser/color_chooser_view.h"
+#include "ui/views/examples/example_base.h"
+
+namespace views::examples {
+
+// A ColorChooser example.
+class VIEWS_EXAMPLES_EXPORT ColorChooserExample : public ExampleBase,
+                                                  public ColorChooserListener {
+ public:
+  ColorChooserExample();
+
+  ColorChooserExample(const ColorChooserExample&) = delete;
+  ColorChooserExample& operator=(const ColorChooserExample&) = delete;
+
+  ~ColorChooserExample() override;
+
+  // ExampleBase:
+  void CreateExampleView(View* container) override;
+
+  // ColorChooserListener:
+  void OnColorChosen(SkColor color) override;
+  void OnColorChooserDialogClosed() override;
+
+ private:
+  ColorChooser chooser_{this, SK_ColorRED};
+};
+
+}  // namespace views::examples
+
+#endif  // UI_VIEWS_EXAMPLES_COLOR_CHOOSER_EXAMPLE_H_
diff --git a/ui/views/examples/create_examples.cc b/ui/views/examples/create_examples.cc
index 37338e8..14d5ad0 100644
--- a/ui/views/examples/create_examples.cc
+++ b/ui/views/examples/create_examples.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "build/build_config.h"
 #include "ui/views/examples/animated_image_view_example.h"
 #include "ui/views/examples/animation_example.h"
 #include "ui/views/examples/ax_example.h"
@@ -45,6 +46,10 @@
 #include "ui/views/examples/vector_example.h"
 #include "ui/views/examples/widget_example.h"
 
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_FUCHSIA)
+#include "ui/views/examples/color_chooser_example.h"
+#endif
+
 namespace views {
 namespace examples {
 
@@ -59,6 +64,9 @@
   examples.push_back(std::make_unique<ButtonExample>());
   examples.push_back(std::make_unique<ButtonStickerSheet>());
   examples.push_back(std::make_unique<CheckboxExample>());
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_FUCHSIA)
+  examples.push_back(std::make_unique<ColorChooserExample>());
+#endif
   examples.push_back(std::make_unique<ColoredDialogExample>());
   examples.push_back(std::make_unique<ColorsExample>());
   examples.push_back(std::make_unique<ComboboxExample>());