diff --git a/DEPS b/DEPS
index fd61281..dddde5d 100644
--- a/DEPS
+++ b/DEPS
@@ -199,11 +199,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'f0cb733b1b1c87a7c17ea365e4e1248301ffe4a6',
+  'skia_revision': 'c8e16bbe32bee288425dc6308f2d55ea3167b1de',
   # 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': '724907341fdd1a17fced5758d13d736c3c19cc6b',
+  'v8_revision': '81b3d28ad43829f5d3c65e0725a266bb1a8e7340',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -211,7 +211,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '7f0e7d0d262aa0ee71c862846c72f737cbbfca04',
+  'angle_revision': 'c0ef8ccfcd8bd983dc3d7469e810ad133b80b4cd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -266,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'd1a3011cd91205aa96b74b5dfc227d391e88108d',
+  'catapult_revision': '3889691dd695c91c212b36d857d73089cb1b8f53',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -274,7 +274,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': 'a60056fee789b9256679a8d1e60f00650303f9af',
+  'devtools_frontend_revision': 'e2ffb37426336eb63db537529022fadf263ebba6',
   # 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.
@@ -314,7 +314,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': '2bd95f1cf45451119b6644e41919b7bef443d912',
+  'dawn_revision': '7fae6cbf1d370bce5af457ad07f97f290a99cb0d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -873,7 +873,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' + '@' + '04314b1d8edbf792cbed36c08c9ca0ee16aa0c88',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'b577a78d937c753c348f38a4b5c47e5f6d369ac8',
       'condition': 'checkout_chromeos',
   },
 
@@ -1266,7 +1266,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '53a231c0ae868366179bd560b68a2f5f4b166541',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '002c03c4b6ed27434ff35dbb31bd8c3288b0ccbd',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1417,16 +1417,6 @@
   'src/third_party/ruy/src':
     Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '34ea9f4993955fa1ff4eb58e504421806b7f2e8f',
 
-  'src/third_party/shaka-player/dist': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/shaka-player',
-              'version': '82FcUTdHazqTIVQG-bKn_oXNI5880G2k_rL0bICTeDgC',
-          },
-      ],
-      'dep_type': 'cipd',
-  },
-
   'src/third_party/skia':
     Var('skia_git') + '/skia.git' + '@' +  Var('skia_revision'),
 
@@ -1590,7 +1580,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@aa6859ae90565a98ff34356f00dac4291b91ed57',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@767ed2f6b6426300b59e73ba70336ce7bf757607',
     'condition': 'checkout_src_internal',
   },
 
@@ -1598,7 +1588,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '3MqI5L2Z8aRLO-u-vkhjeZ2zve9gk6wTyRVsZs18jhUC',
+        'version': 'yhWN-sh7gopLrFlZSwV0PMt236wQVRnoOIc1ppByspUC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1609,7 +1599,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'voP4PTSduZCLb0NO9orrGSgCI4U2hRUPlz6SbHXspy4C',
+        'version': 'CahPFs6jLT-RYm6-kxrLmP917a316i02uOphMFmENT0C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index e75705e2..967a755d 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -715,12 +715,8 @@
     "multi_user/user_switch_animator.h",
     "policy/policy_recommendation_restorer.cc",
     "policy/policy_recommendation_restorer.h",
-    "power/hid_battery_listener.cc",
-    "power/hid_battery_listener.h",
     "power/hid_battery_util.cc",
     "power/hid_battery_util.h",
-    "power/peripheral_battery_tracker.cc",
-    "power/peripheral_battery_tracker.h",
     "quick_answers/quick_answers_controller_impl.cc",
     "quick_answers/quick_answers_controller_impl.h",
     "quick_answers/quick_answers_ui_controller.cc",
@@ -2126,7 +2122,6 @@
     "metrics/user_metrics_recorder_unittest.cc",
     "multi_device_setup/multi_device_notification_presenter_unittest.cc",
     "policy/policy_recommendation_restorer_unittest.cc",
-    "power/hid_battery_listener_unittest.cc",
     "power/hid_battery_util_unittest.cc",
     "quick_answers/quick_answers_controller_unittest.cc",
     "quick_answers/quick_answers_ui_controller_unittest.cc",
diff --git a/ash/accessibility/accessibility_focus_ring_layer.cc b/ash/accessibility/accessibility_focus_ring_layer.cc
index 013eb2b..111fa9a 100644
--- a/ash/accessibility/accessibility_focus_ring_layer.cc
+++ b/ash/accessibility/accessibility_focus_ring_layer.cc
@@ -23,8 +23,8 @@
 // transparent.
 constexpr int kGradientWidth = 6;
 constexpr int kDefaultStrokeWidth = 2;
-constexpr float kDashLengthDip = 3.f;
-constexpr float kGapLengthDip = 5.f;
+constexpr float kDashLengthDip = 4.f;
+constexpr float kGapLengthDip = 2.f;
 
 int sign(int x) {
   return ((x > 0) ? 1 : (x == 0) ? 0 : -1);
@@ -182,23 +182,20 @@
   SkPath path;
   gfx::Vector2d offset = layer()->bounds().OffsetFromOrigin();
 
-  SkScalar intervals[] = {kDashLengthDip, kGapLengthDip};
-  int intervals_length = 2;
-  flags.setPathEffect(SkDashPathEffect::Make(intervals, intervals_length, 0));
-
-  // To keep the dashes properly lined up, we will draw the outside line first,
-  // and cover it with the inner line.
-  flags.setColor(secondary_color_);
-  flags.setStrokeWidth(3 * kDefaultStrokeWidth);
-
-  path = MakePath(ring_, 0, offset);
-  recorder.canvas()->DrawPath(path, flags);
-
   flags.setColor(custom_color());
   flags.setStrokeWidth(kDefaultStrokeWidth);
 
   path = MakePath(ring_, 0, offset);
   recorder.canvas()->DrawPath(path, flags);
+
+  SkScalar intervals[] = {kDashLengthDip, kGapLengthDip};
+  int intervals_length = 2;
+  flags.setPathEffect(SkDashPathEffect::Make(intervals, intervals_length, 0));
+  flags.setColor(secondary_color_);
+
+  path = MakePath(ring_, kDefaultStrokeWidth, offset);
+  recorder.canvas()->DrawPath(path, flags);
+
 }
 
 void AccessibilityFocusRingLayer::DrawGlowFocusRing(ui::PaintRecorder& recorder,
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 822c357..7721fad1 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -869,6 +869,11 @@
   UpdateAppListBackgroundYPosition(app_list_state_);
 }
 
+void AppListView::OnThemeChanged() {
+  views::View::OnThemeChanged();
+  SetBackgroundShieldColor();
+}
+
 ax::mojom::Role AppListView::GetAccessibleWindowRole() {
   // Default role of root view is ax::mojom::Role::kWindow which traps ChromeVox
   // focus within the root view. Assign ax::mojom::Role::kGroup here to allow
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h
index 5690eb7..c5dfcb4 100644
--- a/ash/app_list/views/app_list_view.h
+++ b/ash/app_list/views/app_list_view.h
@@ -186,6 +186,7 @@
   const char* GetClassName() const override;
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
   void Layout() override;
+  void OnThemeChanged() override;
 
   // WidgetDelegate:
   ax::mojom::Role GetAccessibleWindowRole() override;
diff --git a/ash/clipboard/clipboard_history_controller_impl.cc b/ash/clipboard/clipboard_history_controller_impl.cc
index 7dc8caf..4c29f6b6 100644
--- a/ash/clipboard/clipboard_history_controller_impl.cc
+++ b/ash/clipboard/clipboard_history_controller_impl.cc
@@ -205,9 +205,11 @@
           std::make_unique<ClipboardNudgeController>(clipboard_history_.get(),
                                                      this)) {
   clipboard_history_->AddObserver(this);
+  resource_manager_->AddObserver(this);
 }
 
 ClipboardHistoryControllerImpl::~ClipboardHistoryControllerImpl() {
+  resource_manager_->RemoveObserver(this);
   clipboard_history_->RemoveObserver(this);
 }
 
@@ -345,6 +347,15 @@
   return item_results;
 }
 
+std::vector<std::string> ClipboardHistoryControllerImpl::GetHistoryItemIds()
+    const {
+  std::vector<std::string> item_ids;
+  for (const auto& item : history()->GetItems()) {
+    item_ids.push_back(item.id().ToString());
+  }
+  return item_ids;
+}
+
 bool ClipboardHistoryControllerImpl::PasteClipboardItemById(
     const std::string& item_id) {
   if (currently_pasting_)
@@ -370,6 +381,19 @@
   return false;
 }
 
+void ClipboardHistoryControllerImpl::OnClipboardHistoryItemAdded(
+    const ClipboardHistoryItem& item,
+    bool is_duplicate) {
+  for (auto& observer : observers_)
+    observer.OnClipboardHistoryItemListAddedOrRemoved();
+}
+
+void ClipboardHistoryControllerImpl::OnClipboardHistoryItemRemoved(
+    const ClipboardHistoryItem& item) {
+  for (auto& observer : observers_)
+    observer.OnClipboardHistoryItemListAddedOrRemoved();
+}
+
 void ClipboardHistoryControllerImpl::OnClipboardHistoryCleared() {
   // Prevent clipboard contents getting restored if the Clipboard is cleared
   // soon after a `PasteMenuItemData()`.
@@ -380,6 +404,12 @@
   context_menu_.reset();
 }
 
+void ClipboardHistoryControllerImpl::OnCachedImageModelUpdated(
+    const std::vector<base::UnguessableToken>& menu_item_ids) {
+  for (auto& observer : observers_)
+    observer.OnClipboardHistoryItemsUpdated(menu_item_ids);
+}
+
 void ClipboardHistoryControllerImpl::ExecuteSelectedMenuItem(int event_flags) {
   DCHECK(IsMenuShowing());
 
diff --git a/ash/clipboard/clipboard_history_controller_impl.h b/ash/clipboard/clipboard_history_controller_impl.h
index 6ddde181..24e7aec 100644
--- a/ash/clipboard/clipboard_history_controller_impl.h
+++ b/ash/clipboard/clipboard_history_controller_impl.h
@@ -11,6 +11,7 @@
 #include "ash/ash_export.h"
 #include "ash/clipboard/clipboard_history.h"
 #include "ash/clipboard/clipboard_history_item.h"
+#include "ash/clipboard/clipboard_history_resource_manager.h"
 #include "ash/public/cpp/clipboard_history_controller.h"
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
@@ -33,7 +34,8 @@
 // keyboard shortcut is pressed.
 class ASH_EXPORT ClipboardHistoryControllerImpl
     : public ClipboardHistoryController,
-      public ClipboardHistory::Observer {
+      public ClipboardHistory::Observer,
+      public ClipboardHistoryResourceManager::Observer {
  public:
   ClipboardHistoryControllerImpl();
   ClipboardHistoryControllerImpl(const ClipboardHistoryControllerImpl&) =
@@ -89,12 +91,20 @@
   std::unique_ptr<ScopedClipboardHistoryPause> CreateScopedPause() override;
   base::Value GetHistoryValues(
       const std::set<std::string>& item_id_filter) const override;
+  std::vector<std::string> GetHistoryItemIds() const override;
   bool PasteClipboardItemById(const std::string& item_id) override;
   bool DeleteClipboardItemById(const std::string& item_id) override;
 
   // ClipboardHistory::Observer:
+  void OnClipboardHistoryItemAdded(const ClipboardHistoryItem& item,
+                                   bool is_duplicate) override;
+  void OnClipboardHistoryItemRemoved(const ClipboardHistoryItem& item) override;
   void OnClipboardHistoryCleared() override;
 
+  // ClipboardHistoryResourceManager:
+  void OnCachedImageModelUpdated(
+      const std::vector<base::UnguessableToken>& menu_item_ids) override;
+
   void ExecuteSelectedMenuItem(int event_flags);
 
   // Executes the command specified by `command_id` with the given event flags.
diff --git a/ash/clipboard/clipboard_history_controller_unittest.cc b/ash/clipboard/clipboard_history_controller_unittest.cc
index 05effb5..e1336cd 100644
--- a/ash/clipboard/clipboard_history_controller_unittest.cc
+++ b/ash/clipboard/clipboard_history_controller_unittest.cc
@@ -68,6 +68,8 @@
 
   void Deactivate() override {}
 
+  void RenderCurrentPendingRequests() override {}
+
   void OnShutdown() override {}
 };
 
diff --git a/ash/clipboard/clipboard_history_resource_manager_unittest.cc b/ash/clipboard/clipboard_history_resource_manager_unittest.cc
index 885ac19..553d68b 100644
--- a/ash/clipboard/clipboard_history_resource_manager_unittest.cc
+++ b/ash/clipboard/clipboard_history_resource_manager_unittest.cc
@@ -75,6 +75,7 @@
   MOCK_METHOD(void, CancelRequest, (const base::UnguessableToken&), (override));
   MOCK_METHOD(void, Activate, (), (override));
   MOCK_METHOD(void, Deactivate, (), (override));
+  MOCK_METHOD(void, RenderCurrentPendingRequests, (), (override));
   void OnShutdown() override {}
 };
 
diff --git a/ash/power/hid_battery_listener.cc b/ash/power/hid_battery_listener.cc
deleted file mode 100644
index b48d879..0000000
--- a/ash/power/hid_battery_listener.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2019 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/power/hid_battery_listener.h"
-
-#include "ash/power/hid_battery_util.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_device.h"
-
-namespace ash {
-
-HidBatteryListener::HidBatteryListener(
-    scoped_refptr<device::BluetoothAdapter> adapter)
-    : adapter_(adapter) {
-  chromeos::PowerManagerClient::Get()->AddObserver(this);
-  adapter_->AddObserver(this);
-
-  // We may be late for DeviceAdded notifications. So for the already added
-  // devices, simulate DeviceAdded events.
-  for (auto* const device : adapter_->GetDevices())
-    DeviceAdded(adapter_.get(), device);
-}
-
-HidBatteryListener::~HidBatteryListener() {
-  chromeos::PowerManagerClient::Get()->RemoveObserver(this);
-  adapter_->RemoveObserver(this);
-}
-
-void HidBatteryListener::PeripheralBatteryStatusReceived(
-    const std::string& path,
-    const std::string& name,
-    int level) {
-  const std::string bluetooth_address =
-      ExtractBluetoothAddressFromHIDBatteryPath(path);
-  if (bluetooth_address.empty())
-    return;
-
-  device::BluetoothDevice* device = adapter_->GetDevice(bluetooth_address);
-  if (!device)
-    return;
-
-  if (level < 0 || level > 100)
-    device->SetBatteryPercentage(base::nullopt);
-  else
-    device->SetBatteryPercentage(level);
-}
-
-void HidBatteryListener::DeviceAdded(device::BluetoothAdapter* adapter,
-                                     device::BluetoothDevice* device) {
-  chromeos::PowerManagerClient::Get()->RefreshBluetoothBattery(
-      device->GetAddress());
-}
-
-}  // namespace ash
diff --git a/ash/power/hid_battery_listener.h b/ash/power/hid_battery_listener.h
deleted file mode 100644
index 104600e..0000000
--- a/ash/power/hid_battery_listener.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_POWER_HID_BATTERY_LISTENER_H_
-#define ASH_POWER_HID_BATTERY_LISTENER_H_
-
-#include "ash/ash_export.h"
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "chromeos/dbus/power/power_manager_client.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-
-namespace ash {
-
-// Listens to changes in battery level for HID devices, updating the
-// corresponding device::BluetoothDevice.
-// TODO(b/166543531): Remove after migrated to BlueZ Battery Provider API.
-class ASH_EXPORT HidBatteryListener
-    : public chromeos::PowerManagerClient::Observer,
-      public device::BluetoothAdapter::Observer {
- public:
-  explicit HidBatteryListener(scoped_refptr<device::BluetoothAdapter> adapter);
-  ~HidBatteryListener() override;
-
- private:
-  friend class HidBatteryListenerTest;
-
-  // chromeos::PowerManagerClient::Observer:
-  void PeripheralBatteryStatusReceived(const std::string& path,
-                                       const std::string& name,
-                                       int level) override;
-
-  // device::BluetoothAdapter::Observer:
-  void DeviceAdded(device::BluetoothAdapter* adapter,
-                   device::BluetoothDevice* device) override;
-
-  scoped_refptr<device::BluetoothAdapter> adapter_;
-
-  DISALLOW_COPY_AND_ASSIGN(HidBatteryListener);
-};
-
-}  // namespace ash
-
-#endif  // ASH_POWER_HID_BATTERY_LISTENER_H_
diff --git a/ash/power/hid_battery_listener_unittest.cc b/ash/power/hid_battery_listener_unittest.cc
deleted file mode 100644
index 05c5f75..0000000
--- a/ash/power/hid_battery_listener_unittest.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2019 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/power/hid_battery_listener.h"
-
-#include <memory>
-
-#include "ash/test/ash_test_base.h"
-#include "chromeos/dbus/power/fake_power_manager_client.h"
-#include "device/bluetooth/test/mock_bluetooth_adapter.h"
-#include "device/bluetooth/test/mock_bluetooth_device.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::_;
-using testing::NiceMock;
-using testing::Return;
-
-namespace ash {
-namespace {
-
-const char kPath[] = "/sys/class/power_supply/hid-AA:BB:CC:DD:EE:FF-battery";
-const char kAddress[] = "aa:bb:cc:dd:ee:ff";
-const char kDeviceName[] = "test device";
-
-}  // namespace
-
-class HidBatteryListenerTest : public AshTestBase {
- public:
-  HidBatteryListenerTest() = default;
-
-  ~HidBatteryListenerTest() override = default;
-
-  void SetUp() override {
-    AshTestBase::SetUp();
-
-    mock_adapter_ =
-        base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>();
-
-    mock_device_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>(
-        mock_adapter_.get(), 0 /* bluetooth_class */, kDeviceName, kAddress,
-        true /* paired */, true /* connected */);
-    ASSERT_FALSE(mock_device_->battery_percentage());
-    ON_CALL(*mock_adapter_, GetDevice(kAddress))
-        .WillByDefault(Return(mock_device_.get()));
-
-    // Check that HidBatteryListener subscribes to be adapter observer.
-    EXPECT_CALL(*mock_adapter_, AddObserver(_))
-        .WillOnce(testing::SaveArg<0>(&adapter_observer_));
-    listener_ = std::make_unique<HidBatteryListener>(mock_adapter_);
-  }
-
-  void TearDown() override {
-    listener_.reset();
-    AshTestBase::TearDown();
-  }
-
-  void NotifyPeripheralBatteryStatusReceived(const std::string& path,
-                                             const std::string& name,
-                                             int level) {
-    listener_->PeripheralBatteryStatusReceived(path, name, level);
-  }
-
- protected:
-  scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
-  std::unique_ptr<device::MockBluetoothDevice> mock_device_;
-  std::unique_ptr<HidBatteryListener> listener_;
-  device::BluetoothAdapter::Observer* adapter_observer_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(HidBatteryListenerTest);
-};
-
-TEST_F(HidBatteryListenerTest, SetsBatteryToDevice) {
-  NotifyPeripheralBatteryStatusReceived(kPath, kDeviceName, 100);
-  EXPECT_EQ(100, mock_device_->battery_percentage());
-  NotifyPeripheralBatteryStatusReceived(kPath, kDeviceName, 0);
-  EXPECT_EQ(0, mock_device_->battery_percentage());
-  NotifyPeripheralBatteryStatusReceived(kPath, kDeviceName, 55);
-  EXPECT_EQ(55, mock_device_->battery_percentage());
-}
-
-TEST_F(HidBatteryListenerTest, InvalidBatteryLevel) {
-  NotifyPeripheralBatteryStatusReceived(kPath, kDeviceName, 101);
-  EXPECT_EQ(base::nullopt, mock_device_->battery_percentage());
-  NotifyPeripheralBatteryStatusReceived(kPath, kDeviceName, 200);
-  EXPECT_EQ(base::nullopt, mock_device_->battery_percentage());
-  NotifyPeripheralBatteryStatusReceived(kPath, kDeviceName, -1);
-  EXPECT_EQ(base::nullopt, mock_device_->battery_percentage());
-  NotifyPeripheralBatteryStatusReceived(kPath, kDeviceName, -100);
-  EXPECT_EQ(base::nullopt, mock_device_->battery_percentage());
-}
-
-TEST_F(HidBatteryListenerTest, InvalidHIDAddress) {
-  EXPECT_CALL(*mock_adapter_, GetDevice(_)).Times(0);
-
-  NotifyPeripheralBatteryStatusReceived("invalid-path", kDeviceName, 100);
-  NotifyPeripheralBatteryStatusReceived("/sys/class/power_supply/hid-battery",
-                                        kDeviceName, 100);
-
-  // 3 characters at the end of the address, "f55".
-  NotifyPeripheralBatteryStatusReceived(
-      "/sys/class/power_supply/hid-A0:b1:C2:d3:E4:f55-battery", kDeviceName,
-      100);
-
-  // 3 characters at the start of the address, "A00".
-  NotifyPeripheralBatteryStatusReceived(
-      "/sys/class/power_supply/hid-A00:b1:C2:d3:E4:f5-battery", kDeviceName,
-      100);
-}
-
-TEST_F(HidBatteryListenerTest, DeviceNotPresentInAdapter) {
-  ON_CALL(*mock_adapter_, GetDevice(kAddress)).WillByDefault(Return(nullptr));
-
-  // Should not crash.
-  NotifyPeripheralBatteryStatusReceived(kPath, kDeviceName, 100);
-}
-
-TEST_F(HidBatteryListenerTest, RefreshBluetoothBattery) {
-  // Start with no battery info.
-  EXPECT_FALSE(mock_device_->battery_percentage());
-
-  // Simulate DeviceAdded observer event.
-  chromeos::FakePowerManagerClient::Get()->set_peripheral_battery_refresh_level(
-      kAddress, 60);
-  adapter_observer_->DeviceAdded(mock_adapter_.get(), mock_device_.get());
-  EXPECT_EQ(60, mock_device_->battery_percentage());
-
-  // Simulate DeviceAdded observer event with a different battery value.
-  chromeos::FakePowerManagerClient::Get()->set_peripheral_battery_refresh_level(
-      kAddress, 50);
-  adapter_observer_->DeviceAdded(mock_adapter_.get(), mock_device_.get());
-  EXPECT_EQ(50, mock_device_->battery_percentage());
-}
-
-}  // namespace ash
diff --git a/ash/power/peripheral_battery_tracker.cc b/ash/power/peripheral_battery_tracker.cc
deleted file mode 100644
index 304eb00..0000000
--- a/ash/power/peripheral_battery_tracker.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2019 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/power/peripheral_battery_tracker.h"
-
-#include "ash/power/hid_battery_listener.h"
-#include "base/bind.h"
-#include "base/check.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
-
-namespace ash {
-
-PeripheralBatteryTracker::PeripheralBatteryTracker() {
-  device::BluetoothAdapterFactory::Get()->GetAdapter(
-      base::BindOnce(&PeripheralBatteryTracker::InitializeOnBluetoothReady,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-PeripheralBatteryTracker::~PeripheralBatteryTracker() = default;
-
-void PeripheralBatteryTracker::InitializeOnBluetoothReady(
-    scoped_refptr<device::BluetoothAdapter> adapter) {
-  adapter_ = adapter;
-  DCHECK(adapter_.get());
-  hid_battery_listener_ = std::make_unique<HidBatteryListener>(adapter_);
-  // GATT and HFP Battery reporting is handled by
-  // device::BluetoothBatteryClient.
-}
-
-}  // namespace ash
diff --git a/ash/power/peripheral_battery_tracker.h b/ash/power/peripheral_battery_tracker.h
deleted file mode 100644
index e51113b..0000000
--- a/ash/power/peripheral_battery_tracker.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_POWER_PERIPHERAL_BATTERY_TRACKER_H_
-#define ASH_POWER_PERIPHERAL_BATTERY_TRACKER_H_
-
-#include "ash/ash_export.h"
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-
-namespace device {
-class BluetoothAdapter;
-}  // namespace device
-
-namespace ash {
-
-class HfpBatteryListener;
-class HidBatteryListener;
-
-// Creates instances of classes to collect the battery status of peripheral
-// devices. Currently only tracks Bluetooth devices that support GATT, HFP or
-// HID.
-class ASH_EXPORT PeripheralBatteryTracker {
- public:
-  PeripheralBatteryTracker();
-  ~PeripheralBatteryTracker();
-
- private:
-  void InitializeOnBluetoothReady(
-      scoped_refptr<device::BluetoothAdapter> adapter);
-
-  scoped_refptr<device::BluetoothAdapter> adapter_;
-
-  std::unique_ptr<HidBatteryListener> hid_battery_listener_;
-
-  base::WeakPtrFactory<PeripheralBatteryTracker> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(PeripheralBatteryTracker);
-};
-
-}  // namespace ash
-
-#endif  // ASH_POWER_PERIPHERAL_BATTERY_TRACKER_H_
diff --git a/ash/public/cpp/clipboard_history_controller.h b/ash/public/cpp/clipboard_history_controller.h
index 07d1379..3e81d3dc 100644
--- a/ash/public/cpp/clipboard_history_controller.h
+++ b/ash/public/cpp/clipboard_history_controller.h
@@ -14,6 +14,7 @@
 
 namespace base {
 class Value;
+class UnguessableToken;
 }  // namespace base
 
 namespace gfx {
@@ -33,6 +34,12 @@
     virtual void OnClipboardHistoryMenuShown() {}
     // Called when the user pastes from the clipboard history menu.
     virtual void OnClipboardHistoryPasted() {}
+    // Called when the clipboard history changes.
+    virtual void OnClipboardHistoryItemListAddedOrRemoved() {}
+    // Called when existing clipboard items in the history have changes.
+    // virtual void OnClipboardHistoryItemsUpdated(
+    virtual void OnClipboardHistoryItemsUpdated(
+        const std::vector<base::UnguessableToken>& menu_item_ids) {}
   };
 
   // Returns the singleton instance.
@@ -59,6 +66,9 @@
   virtual base::Value GetHistoryValues(
       const std::set<std::string>& item_id_filter) const = 0;
 
+  // Returns a list of item ids for items contained in the clipboard history.
+  virtual std::vector<std::string> GetHistoryItemIds() const = 0;
+
   // Pastes the clipboard item specified by the item id.
   virtual bool PasteClipboardItemById(const std::string& item_id) = 0;
 
diff --git a/ash/public/cpp/clipboard_image_model_factory.h b/ash/public/cpp/clipboard_image_model_factory.h
index 59c9423..753d688 100644
--- a/ash/public/cpp/clipboard_image_model_factory.h
+++ b/ash/public/cpp/clipboard_image_model_factory.h
@@ -44,9 +44,19 @@
   // state and all rendering requests will be queued until activated.
   virtual void Activate() = 0;
 
-  // Called after Activate() to pause rendering requests.
+  // Called after Activate() to pause rendering requests. Rendering requests
+  // will will continue until all requests are processed if
+  // RenderCurrentPendingRequests() has been called.
   virtual void Deactivate() = 0;
 
+  // Called to render all currently pending requests. This is called when the
+  // virtual keyboard private api calls getClipboardHistory, so that clipboard
+  // history items that are displayed will be rendered. Since there is no way to
+  // track when the clipboard history is shown/hidden in the virtual keyboard,
+  // this is called to ensure the current clipboard history is rendered.
+  // Convenience function to `Activate()` until all requests are finished.
+  virtual void RenderCurrentPendingRequests() = 0;
+
   // Called during shutdown to cleanup references to Profile.
   virtual void OnShutdown() = 0;
 
diff --git a/ash/public/cpp/holding_space/holding_space_constants.h b/ash/public/cpp/holding_space/holding_space_constants.h
index aea8462..668799d0 100644
--- a/ash/public/cpp/holding_space/holding_space_constants.h
+++ b/ash/public/cpp/holding_space/holding_space_constants.h
@@ -21,14 +21,10 @@
 constexpr int kHoldingSpaceCornerRadius = 8;
 constexpr int kHoldingSpaceDownloadsChevronIconSize = 20;
 constexpr int kHoldingSpaceDownloadsHeaderSpacing = 16;
-constexpr int kHoldingSpaceFocusInsets = -2;
+constexpr int kHoldingSpaceFocusCornerRadius = 12;
+constexpr int kHoldingSpaceFocusInsets = -4;
 constexpr int kHoldingSpaceIconSize = 20;
-constexpr gfx::Insets kHoldingSpaceScreenCapturePadding(8);
-constexpr gfx::Size kHoldingSpaceScreenCapturePinButtonSize(24, 24);
-constexpr gfx::Size kHoldingSpaceScreenCapturePlayIconSize(32, 32);
-constexpr int kHoldingSpaceScreenCaptureSpacing = 8;
 constexpr gfx::Size kHoldingSpaceScreenCaptureSize(104, 80);
-constexpr gfx::Insets kHoldingSpaceScreenCapturesContainerPadding(8, 0);
 constexpr int kHoldingSpaceSectionChildSpacing = 16;
 constexpr float kHoldingSpaceSelectedOverlayOpacity = 0.24f;
 constexpr int kHoldingSpaceTrayIconMaxVisiblePreviews = 3;
diff --git a/ash/public/cpp/test/shell_test_api.h b/ash/public/cpp/test/shell_test_api.h
index 5fa468ba..08a6a738 100644
--- a/ash/public/cpp/test/shell_test_api.h
+++ b/ash/public/cpp/test/shell_test_api.h
@@ -116,10 +116,6 @@
   // It returns nullptr when app-list is not shown.
   PaginationModel* GetAppListPaginationModel();
 
-  // Shows the context menu associated with the primary root window at point (1,
-  // 1).
-  void ShowContextMenu();
-
   // Returns true if the context menu associated with the primary root window is
   // shown.
   bool IsContextMenuShown() const;
diff --git a/ash/shell.cc b/ash/shell.cc
index 11fb4272..d2ea482a 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -74,7 +74,6 @@
 #include "ash/media/media_notification_controller_impl.h"
 #include "ash/multi_device_setup/multi_device_notification_presenter.h"
 #include "ash/policy/policy_recommendation_restorer.h"
-#include "ash/power/peripheral_battery_tracker.h"
 #include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_prefs.h"
@@ -944,10 +943,6 @@
 
   peripheral_battery_notifier_ = std::make_unique<PeripheralBatteryNotifier>(
       peripheral_battery_listener_.get());
-  if (base::FeatureList::IsEnabled(
-          chromeos::features::kShowBluetoothDeviceBattery)) {
-    peripheral_battery_tracker_ = std::make_unique<PeripheralBatteryTracker>();
-  }
   power_event_observer_.reset(new PowerEventObserver());
 
   if (features::IsCaptureModeEnabled()) {
diff --git a/ash/shell.h b/ash/shell.h
index 7e0278e..9259c43 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -152,7 +152,6 @@
 class PartialMagnificationController;
 class PeripheralBatteryListener;
 class PeripheralBatteryNotifier;
-class PeripheralBatteryTracker;
 class PersistentWindowController;
 class PolicyRecommendationRestorer;
 class PowerButtonController;
@@ -793,7 +792,6 @@
 
   std::unique_ptr<PeripheralBatteryListener> peripheral_battery_listener_;
   std::unique_ptr<PeripheralBatteryNotifier> peripheral_battery_notifier_;
-  std::unique_ptr<PeripheralBatteryTracker> peripheral_battery_tracker_;
   std::unique_ptr<PowerEventObserver> power_event_observer_;
   std::unique_ptr<PowerPrefs> power_prefs_;
   std::unique_ptr<ui::UserActivityPowerManagerNotifier> user_activity_notifier_;
diff --git a/ash/shell_test_api.cc b/ash/shell_test_api.cc
index 7ee941eb..a1f92006 100644
--- a/ash/shell_test_api.cc
+++ b/ash/shell_test_api.cc
@@ -252,11 +252,6 @@
   return view->GetAppsPaginationModel();
 }
 
-void ShellTestApi::ShowContextMenu() {
-  Shell::GetPrimaryRootWindowController()->ShowContextMenu(
-      gfx::Point(1, 1), ui::MENU_SOURCE_MOUSE);
-}
-
 bool ShellTestApi::IsContextMenuShown() const {
   return Shell::GetPrimaryRootWindowController()->IsContextMenuShown();
 }
diff --git a/ash/system/holding_space/holding_space_item_screen_capture_view.cc b/ash/system/holding_space/holding_space_item_screen_capture_view.cc
index 610fa2b..4b0d92f 100644
--- a/ash/system/holding_space/holding_space_item_screen_capture_view.cc
+++ b/ash/system/holding_space/holding_space_item_screen_capture_view.cc
@@ -23,6 +23,11 @@
 
 namespace ash {
 
+// Appearance.
+constexpr gfx::Insets kPinButtonMargins(4);
+constexpr gfx::Size kPinButtonSize(24, 24);
+constexpr gfx::Size kPlayIconSize(32, 32);
+
 HoldingSpaceItemScreenCaptureView::HoldingSpaceItemScreenCaptureView(
     HoldingSpaceItemViewDelegate* delegate,
     const HoldingSpaceItem* item)
@@ -48,8 +53,7 @@
 
   auto* layout =
       pin_button_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
-          views::BoxLayout::Orientation::kHorizontal,
-          kHoldingSpaceScreenCapturePadding));
+          views::BoxLayout::Orientation::kHorizontal, kPinButtonMargins));
   layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kEnd);
   layout->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kStart);
@@ -59,8 +63,8 @@
   // Create contrasting background for the pin icon.
   pin->SetBackground(views::CreateRoundedRectBackground(
       HoldingSpaceColorProvider::Get()->GetBackgroundColor(),
-      kHoldingSpaceScreenCapturePinButtonSize.width() / 2));
-  pin->SetPreferredSize(kHoldingSpaceScreenCapturePinButtonSize);
+      kPinButtonSize.width() / 2));
+  pin->SetPreferredSize(kPinButtonSize);
 }
 
 HoldingSpaceItemScreenCaptureView::~HoldingSpaceItemScreenCaptureView() =
@@ -108,12 +112,12 @@
       vector_icons::kPlayArrowIcon, kHoldingSpaceIconSize,
       AshColorProvider::Get()->GetContentLayerColor(
           AshColorProvider::ContentLayerType::kButtonIconColor)));
-  play_icon->SetPreferredSize(kHoldingSpaceScreenCapturePlayIconSize);
+  play_icon->SetPreferredSize(kPlayIconSize);
 
   // Create contrasting background for the play icon.
   play_icon->SetBackground(views::CreateRoundedRectBackground(
       HoldingSpaceColorProvider::Get()->GetBackgroundColor(),
-      kHoldingSpaceScreenCapturePlayIconSize.width() / 2));
+      kPlayIconSize.width() / 2));
 }
 
 BEGIN_METADATA(HoldingSpaceItemScreenCaptureView, HoldingSpaceItemView)
diff --git a/ash/system/holding_space/holding_space_item_view.cc b/ash/system/holding_space/holding_space_item_view.cc
index 74f9511..66eb6a04 100644
--- a/ash/system/holding_space/holding_space_item_view.cc
+++ b/ash/system/holding_space/holding_space_item_view.cc
@@ -170,15 +170,17 @@
 }
 
 void HoldingSpaceItemView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  // Inset `bounds` to account for stroke.
   gfx::Rect bounds = GetLocalBounds();
+  bounds.Inset(-gfx::Insets(views::PlatformStyle::kFocusHaloThickness / 2));
+
+  // Selection ring.
   selected_layer_owner_->layer()->SetBounds(bounds);
   InvalidateLayer(selected_layer_owner_->layer());
 
-  // The focus ring is painted just outside the bounds for this view.
-  const float kFocusInsets = kHoldingSpaceFocusInsets -
-                             (views::PlatformStyle::kFocusHaloThickness / 2.f);
-
-  bounds.Inset(gfx::Insets(kFocusInsets));
+  // Focus ring.
+  // NOTE: The focus ring is painted just outside the bounds for this view.
+  bounds.Inset(gfx::Insets(kHoldingSpaceFocusInsets));
   focused_layer_owner_->layer()->SetBounds(bounds);
   InvalidateLayer(focused_layer_owner_->layer());
 }
@@ -297,7 +299,7 @@
 
   gfx::Rect bounds = gfx::Rect(size);
   bounds.Inset(gfx::Insets(flags.getStrokeWidth() / 2));
-  canvas->DrawRoundRect(bounds, kHoldingSpaceCornerRadius, flags);
+  canvas->DrawRoundRect(bounds, kHoldingSpaceFocusCornerRadius, flags);
 }
 
 void HoldingSpaceItemView::OnPaintSelect(gfx::Canvas* canvas, gfx::Size size) {
diff --git a/ash/system/holding_space/holding_space_tray.cc b/ash/system/holding_space/holding_space_tray.cc
index 5daa7d15..71171751 100644
--- a/ash/system/holding_space/holding_space_tray.cc
+++ b/ash/system/holding_space/holding_space_tray.cc
@@ -192,13 +192,18 @@
   return bubble_ ? bubble_->GetBubbleView() : nullptr;
 }
 
-void HoldingSpaceTray::SetVisiblePreferred(bool preferred_visibility) {
-  if (visible_preferred() != preferred_visibility) {
-    holding_space_metrics::RecordPodAction(
-        preferred_visibility ? holding_space_metrics::PodAction::kShowPod
-                             : holding_space_metrics::PodAction::kHidePod);
-    TrayBackgroundView::SetVisiblePreferred(preferred_visibility);
-  }
+void HoldingSpaceTray::SetVisiblePreferred(bool visible_preferred) {
+  if (this->visible_preferred() == visible_preferred)
+    return;
+
+  holding_space_metrics::RecordPodAction(
+      visible_preferred ? holding_space_metrics::PodAction::kShowPod
+                        : holding_space_metrics::PodAction::kHidePod);
+
+  TrayBackgroundView::SetVisiblePreferred(visible_preferred);
+
+  if (!visible_preferred)
+    CloseBubble();
 }
 
 void HoldingSpaceTray::FirePreviewsUpdateTimerIfRunningForTesting() {
diff --git a/ash/system/holding_space/screen_captures_section.cc b/ash/system/holding_space/screen_captures_section.cc
index 6f9f06f7..2d365ecb 100644
--- a/ash/system/holding_space/screen_captures_section.cc
+++ b/ash/system/holding_space/screen_captures_section.cc
@@ -17,6 +17,9 @@
 
 namespace ash {
 
+// Appearance.
+constexpr int kChildSpacing = 8;
+
 ScreenCapturesSection::ScreenCapturesSection(
     HoldingSpaceItemViewDelegate* delegate)
     : HoldingSpaceItemViewsSection(delegate,
@@ -47,7 +50,7 @@
       ->SetOrientation(views::LayoutOrientation::kHorizontal)
       .SetDefault(views::kMarginsKey,
                   gfx::Insets(/*top=*/0, /*left=*/0, /*bottom=*/0,
-                              /*right=*/kHoldingSpaceScreenCaptureSpacing));
+                              /*right=*/kChildSpacing));
   return container;
 }
 
diff --git a/ash/wm/gestures/wm_gesture_handler.cc b/ash/wm/gestures/wm_gesture_handler.cc
index 058b042..bd5cb12 100644
--- a/ash/wm/gestures/wm_gesture_handler.cc
+++ b/ash/wm/gestures/wm_gesture_handler.cc
@@ -53,13 +53,6 @@
          pref->GetBoolean(prefs::kNaturalScroll);
 }
 
-// Is reverse scrolling for mouse wheel on.
-bool IsReverseScrollOn() {
-  PrefService* pref =
-      Shell::Get()->session_controller()->GetActivePrefService();
-  return pref->GetBoolean(prefs::kMouseReverseScroll);
-}
-
 // Reverse an offset when the reverse scrolling is on.
 float GetOffset(float offset) {
   // The handler code uses the new directions which is the reverse of the old
@@ -204,24 +197,6 @@
 
 WmGestureHandler::~WmGestureHandler() = default;
 
-bool WmGestureHandler::ProcessWheelEvent(const ui::MouseEvent& event) {
-  if (event.IsMouseWheelEvent() &&
-      Shell::Get()->window_cycle_controller()->IsCycling()) {
-    if (!scroll_data_)
-      scroll_data_ = ScrollData();
-
-    // Convert mouse wheel events into three-finger scrolls for window cycle
-    // list and also swap y offset with x offset.
-    return ProcessEventImpl(
-        /*finger_count=*/3,
-        IsReverseScrollOn() ? event.AsMouseWheelEvent()->y_offset()
-                            : -event.AsMouseWheelEvent()->y_offset(),
-        event.AsMouseWheelEvent()->x_offset());
-  }
-
-  return false;
-}
-
 bool WmGestureHandler::ProcessScrollEvent(const ui::ScrollEvent& event) {
   // ET_SCROLL_FLING_CANCEL means a touchpad swipe has started.
   if (event.type() == ui::ET_SCROLL_FLING_CANCEL) {
@@ -248,8 +223,8 @@
   if (!scroll_data_)
     return false;
 
-  // Only two, three or four finger scrolls are supported.
-  if (finger_count != 2 && finger_count != 3 && finger_count != 4) {
+  // Only three or four finger scrolls are supported.
+  if (finger_count != 3 && finger_count != 4) {
     scroll_data_.reset();
     return false;
   }
@@ -261,21 +236,12 @@
     return false;
   }
 
-  if (finger_count == 2 && !IsNaturalScrollOn()) {
-    // Two finger swipe from left to right should move the list right regardless
-    // of natural scroll settings.
-    delta_x = -delta_x;
-  }
-
   scroll_data_->scroll_x += delta_x;
   scroll_data_->scroll_y += delta_y;
 
-  // If the requirements to cycle the window cycle list or  move the overview
-  // selector are met, reset |scroll_data_|. If both are open, cycle the window
-  // cycle list.
-  const bool moved = CycleWindowCycleList(finger_count, scroll_data_->scroll_x,
-                                          scroll_data_->scroll_y) ||
-                     MoveOverviewSelection(finger_count, scroll_data_->scroll_x,
+  // If the requirements to move the overview selector are met, reset
+  // |scroll_data_|.
+  const bool moved = MoveOverviewSelection(finger_count, scroll_data_->scroll_x,
                                            scroll_data_->scroll_y);
 
   if (is_enhanced_desk_animations_ && finger_count == 4) {
@@ -358,25 +324,6 @@
   return true;
 }
 
-bool WmGestureHandler::CycleWindowCycleList(int finger_count,
-                                            float scroll_x,
-                                            float scroll_y) {
-  if (!features::IsInteractiveWindowCycleListEnabled() ||
-      (finger_count != 2 && finger_count != 3)) {
-    return false;
-  }
-
-  auto* window_cycle_controller = Shell::Get()->window_cycle_controller();
-  const bool is_cycling = window_cycle_controller->IsCycling();
-  if (!ShouldHorizontallyScroll(is_cycling, scroll_x, scroll_y))
-    return false;
-
-  window_cycle_controller->HandleCycleWindow(
-      scroll_x > 0 ? WindowCycleController::FORWARD
-                   : WindowCycleController::BACKWARD);
-  return true;
-}
-
 bool WmGestureHandler::ShouldHorizontallyScroll(bool in_session,
                                                 float scroll_x,
                                                 float scroll_y) {
diff --git a/ash/wm/gestures/wm_gesture_handler.h b/ash/wm/gestures/wm_gesture_handler.h
index 2e4287d..a41fdcc3 100644
--- a/ash/wm/gestures/wm_gesture_handler.h
+++ b/ash/wm/gestures/wm_gesture_handler.h
@@ -10,28 +10,15 @@
 #include "components/prefs/pref_registry_simple.h"
 
 namespace ui {
-class MouseEvent;
 class ScrollEvent;
 }
 
 namespace ash {
 
-// TODO(chinsenj): Consider renaming this to WmEventHandler and moving to parent
-// directory since this now handles mouse wheel events.
-
 // This handles the following interactions:
 //   - 3-finger touchpad scroll events to enter/exit overview mode and move the
 //   overview highlight if it is visible.
 //   - 4-finger horizontal scrolls to switch desks.
-//
-// This handles the following interactions if the InteractiveWindowCycleList
-// flag is enabled. TODO(chinsenj): Merge these comments when the flag is
-// removed.
-//   - 3-finger horizontal touchpad scroll events to cycle the window cycle
-//   list.
-//   - 2-finger horizontal touchpad scroll events to cycle the window cycle
-//   list.
-//   - Mouse wheel events to cycle the window cycle list.
 class ASH_EXPORT WmGestureHandler {
  public:
   // The thresholds of performing a wm action with a touchpad three or four
@@ -49,15 +36,9 @@
   WmGestureHandler& operator=(const WmGestureHandler&) = delete;
   virtual ~WmGestureHandler();
 
-  // Processes a mouse wheel event and may cycle the window cycle list. Returns
-  // true if the event has been handled and should not be processed further,
-  // false otherwise.
-  bool ProcessWheelEvent(const ui::MouseEvent& event);
-
-  // Processes a scroll event and may switch desks, start overview, move the
-  // overview highlight or cycle the window cycle list. Returns true if
-  // the event has been handled and should not be processed further, false
-  // otherwise.
+  // Processes a scroll event and may switch desks, start overview or move the
+  // overview highlight. Returns true if the event has been handled and should
+  // not be processed further, false otherwise.
   bool ProcessScrollEvent(const ui::ScrollEvent& event);
 
  private:
@@ -75,9 +56,8 @@
     bool continuous_gesture_started = false;
   };
 
-  // Called by ProcessWheelEvent() and ProcessScrollEvent(). Depending on
-  // |finger_count|, may switch desks, start overview, move the overview
-  // highlight or cycle the window cycle list. Returns true if the
+  // Called by ProcessScrollEvent(). Depending on |finger_count|, may switch
+  // desks, start overview or move the overview highlight. Returns true if the
   // event has been handled and should not be processed further, false
   // otherwise. Forwards events to DesksController if
   // |is_enhanced_desk_animations_| is true.
@@ -90,12 +70,8 @@
   // the middle of scrolls and when scrolls have ended.
   bool MoveOverviewSelection(int finger_count, float scroll_x, float scroll_y);
 
-  // Tries to cycle the window cycle list. Returns true if successful.
-  // Called in the middle of scrolls and when scrolls have ended.
-  bool CycleWindowCycleList(int finger_count, float scroll_x, float scroll_y);
-
-  // Returns whether or not a given session of overview/window cycle list should
-  // horizontally scroll.
+  // Returns whether or not a given session of overview should horizontally
+  // scroll.
   bool ShouldHorizontallyScroll(bool in_session,
                                 float scroll_x,
                                 float scroll_y);
diff --git a/ash/wm/gestures/wm_gesture_handler_unittest.cc b/ash/wm/gestures/wm_gesture_handler_unittest.cc
index e6b2dec..d870555f 100644
--- a/ash/wm/gestures/wm_gesture_handler_unittest.cc
+++ b/ash/wm/gestures/wm_gesture_handler_unittest.cc
@@ -33,7 +33,6 @@
 
 namespace {
 
-constexpr int kNumFingersForWindowCycle = 2;
 constexpr int kNumFingersForHighlight = 3;
 constexpr int kNumFingersForDesksSwitch = 4;
 
@@ -380,196 +379,6 @@
   EXPECT_EQ(desk_controller->desks()[0].get(), desk_controller->active_desk());
 }
 
-class InteractiveWindowCycleListGestureHandlerTest
-    : public WmGestureHandlerTest {
- public:
-  InteractiveWindowCycleListGestureHandlerTest() = default;
-  InteractiveWindowCycleListGestureHandlerTest(
-      const InteractiveWindowCycleListGestureHandlerTest&) = delete;
-  InteractiveWindowCycleListGestureHandlerTest& operator=(
-      const InteractiveWindowCycleListGestureHandlerTest&) = delete;
-  ~InteractiveWindowCycleListGestureHandlerTest() override = default;
-
-  // AshTestBase:
-  void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kInteractiveWindowCycleList);
-    AshTestBase::SetUp();
-    WindowCycleList::DisableInitialDelayForTesting();
-  }
-
-  int GetCurrentIndex() const {
-    return Shell::Get()
-        ->window_cycle_controller()
-        ->window_cycle_list()
-        ->current_index_for_testing();
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-// Tests three finger horizontal scroll gesture to move selection left or right.
-TEST_F(InteractiveWindowCycleListGestureHandlerTest,
-       ThreeFingerHorizontalScrollInWindowCycleList) {
-  const gfx::Rect bounds(0, 0, 400, 400);
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
-  const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
-
-  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
-                                                            float y_offset) {
-    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
-    controller->StartCycling();
-    Scroll(GetOffsetX(x_offset), GetOffsetY(y_offset), kNumFingersForHighlight);
-    controller->CompleteCycling();
-  };
-
-  // Start cycle, simulating alt key being held down. Scroll right to fourth
-  // item.
-  // Current order is [5,4,3,2,1].
-  scroll_until_window_highlighted_and_confirm(horizontal_scroll * 3, 0);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-
-  // Start cycle. Scroll left to third item.
-  // Current order is [2,5,4,3,1].
-  scroll_until_window_highlighted_and_confirm(-horizontal_scroll * 3, 0);
-  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
-
-  // Start cycle. Scroll right to second item.
-  // Current order is [4,2,5,3,1].
-  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-
-  // Open an overview session and window cycle list. Scroll right to second
-  // item. Scroll should only go to the window cycle list.
-  // Current order is [2,4,5,3,1].
-  Shell::Get()->overview_controller()->StartOverview();
-  EXPECT_TRUE(InOverviewSession());
-
-  Shell::Get()->window_cycle_controller()->StartCycling();
-  Scroll(GetOffsetX(horizontal_scroll), 0, kNumFingersForHighlight);
-  EXPECT_EQ(nullptr, GetHighlightedWindow());
-
-  Shell::Get()->window_cycle_controller()->CompleteCycling();
-  EXPECT_FALSE(InOverviewSession());
-  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
-}
-
-// Tests two finger horizontal scroll gesture to move selection left or right.
-TEST_F(InteractiveWindowCycleListGestureHandlerTest,
-       TwoFingerHorizontalScrollInWindowCycleList) {
-  const gfx::Rect bounds(0, 0, 400, 400);
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
-  const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
-
-  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
-                                                            float y_offset) {
-    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
-    controller->StartCycling();
-    // Since two finger swipes are negated, negate in tests to mimic how this
-    // actually behaves on devices.
-    Scroll(GetOffsetX(-x_offset), GetOffsetY(y_offset),
-           kNumFingersForWindowCycle);
-    controller->CompleteCycling();
-  };
-
-  // Start cycle, simulating alt key being held down. Scroll right to fourth
-  // item.
-  // Current order is [5,4,3,2,1].
-  scroll_until_window_highlighted_and_confirm(horizontal_scroll * 3, 0);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-
-  // Start cycle. Scroll left to third item.
-  // Current order is [2,5,4,3,1].
-  scroll_until_window_highlighted_and_confirm(-horizontal_scroll * 3, 0);
-  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
-
-  // Start cycle. Scroll right to second item.
-  // Current order is [4,2,5,3,1].
-  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-}
-
-// Tests mouse wheel scroll gesture to move selection left or right.
-TEST_F(InteractiveWindowCycleListGestureHandlerTest,
-       MouseWheelScrollInWindowCycleList) {
-  const gfx::Rect bounds(0, 0, 400, 400);
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
-  const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
-
-  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
-                                                            float y_offset,
-                                                            int num_of_times) {
-    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
-    controller->StartCycling();
-    MouseWheelScroll(x_offset, y_offset, num_of_times);
-    controller->CompleteCycling();
-  };
-
-  // Start cycle, simulating alt key being held down. Scroll right to fourth
-  // item.
-  // Current order is [5,4,3,2,1].
-  scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 3);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-
-  // Start cycle. Scroll left to third item.
-  // Current order is [2,5,4,3,1].
-  scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 3);
-  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
-
-  // Start cycle. Scroll right to second item.
-  // Current order is [4,2,5,3,1].
-  scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 1);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-}
-
-// Tests that swiping up closes window cycle if it's open and starts overview
-// mode.
-// TODO(chinsenj): Add this test to
-// WmGestureHandlerTest.VerticalScrolls after this feature is launched.
-TEST_F(InteractiveWindowCycleListGestureHandlerTest, VerticalScroll) {
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow();
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow();
-  const float vertical_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
-  const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
-  auto* window_cycle_controller = Shell::Get()->window_cycle_controller();
-
-  // Start cycling and then swipe up to open up overview.
-  window_cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_TRUE(window_cycle_controller->IsCycling());
-  Scroll(0, vertical_scroll, 3);
-  EXPECT_TRUE(InOverviewSession());
-  EXPECT_FALSE(window_cycle_controller->IsCycling());
-
-  // Start cycling and then swipe down.
-  window_cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_TRUE(window_cycle_controller->IsCycling());
-  Scroll(0, -vertical_scroll, 3);
-  EXPECT_TRUE(window_cycle_controller->IsCycling());
-
-  // Swipe diagonally with horizontal bias.
-  Scroll(horizontal_scroll * 3, vertical_scroll, 3);
-  EXPECT_TRUE(window_cycle_controller->IsCycling());
-  EXPECT_FALSE(InOverviewSession());
-
-  // Swipe diagonally with vertical bias.
-  Scroll(horizontal_scroll, vertical_scroll, 3);
-  EXPECT_FALSE(window_cycle_controller->IsCycling());
-  EXPECT_TRUE(InOverviewSession());
-}
-
 class ReverseGestureHandlerTest : public WmGestureHandlerTest {
  public:
   ReverseGestureHandlerTest() = default;
@@ -580,10 +389,7 @@
 
   // AshTestBase:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures(
-        {features::kInteractiveWindowCycleList,
-         features::kReverseScrollGestures},
-        {});
+    scoped_feature_list_.InitAndEnableFeature(features::kReverseScrollGestures);
     AshTestBase::SetUp();
 
     // Set natural scroll on.
@@ -633,108 +439,4 @@
   EXPECT_EQ(desk1, GetActiveDesk());
 }
 
-// Tests mouse wheel scroll gesture to move selection left or right. Mouse
-// reverse scroll should reverse its direction.
-TEST_F(ReverseGestureHandlerTest, MouseWheelScrollInWindowCycleList) {
-  const gfx::Rect bounds(0, 0, 400, 400);
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
-  const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
-
-  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
-                                                            float y_offset,
-                                                            int num_of_times) {
-    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
-    controller->StartCycling();
-    MouseWheelScroll(x_offset, y_offset, num_of_times);
-    controller->CompleteCycling();
-  };
-
-  // Start cycle, simulating alt key being held down. Scroll right to fourth
-  // item.
-  // Current order is [5,4,3,2,1].
-  scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 3);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-
-  // Start cycle. Scroll left to third item.
-  // Current order is [2,5,4,3,1].
-  scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 3);
-  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
-
-  // Start cycle. Scroll right to second item.
-  // Current order is [4,2,5,3,1].
-  scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 1);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-
-  // Turn mouse reverse scroll off.
-  PrefService* pref =
-      Shell::Get()->session_controller()->GetActivePrefService();
-  pref->SetBoolean(prefs::kMouseReverseScroll, false);
-
-  // Start cycle. Scroll left once.
-  // Current order is [2,4,5,3,1].
-  scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 1);
-  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
-
-  // Start cycle. Scroll right once.
-  // Current order is [1,2,4,5,3].
-  scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 1);
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-}
-
-// Tests that natural scroll doesn't affect two and three finger horizontal
-// scroll gestures for cycling window cycle list.
-TEST_F(ReverseGestureHandlerTest, WindowCycleListTrackpadGestures) {
-  const gfx::Rect bounds(0, 0, 400, 400);
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
-  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
-  const float horizontal_scroll = WmGestureHandler::kHorizontalThresholdDp;
-
-  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
-                                                            float y_offset,
-                                                            int num_fingers) {
-    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
-    controller->StartCycling();
-    Scroll(x_offset, y_offset, num_fingers);
-    controller->CompleteCycling();
-  };
-
-  // Start cycle, scroll right with two finger gesture.
-  // Current order is [5,4,3,2,1].
-  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
-                                              kNumFingersForWindowCycle);
-  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
-
-  // Start cycle, scroll right with three finger gesture.
-  // Current order is [4,5,3,2,1].
-  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
-                                              kNumFingersForHighlight);
-  EXPECT_TRUE(wm::IsActiveWindow(window5.get()));
-
-  // Turn natural scroll off.
-  PrefService* pref =
-      Shell::Get()->session_controller()->GetActivePrefService();
-  pref->SetBoolean(prefs::kNaturalScroll, false);
-
-  // Start cycle, scroll right with two finger gesture. Note: two figner swipes
-  // are negated, so negate in tests to mimic how this actually behaves on
-  // devices.
-  // Current order is [5,4,3,2,1].
-  scroll_until_window_highlighted_and_confirm(-horizontal_scroll, 0,
-                                              kNumFingersForWindowCycle);
-  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
-
-  // Start cycle, scroll right with three finger gesture.
-  // Current order is [4,5,3,2,1].
-  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
-                                              kNumFingersForHighlight);
-  EXPECT_TRUE(wm::IsActiveWindow(window5.get()));
-}
-
 }  // namespace ash
diff --git a/ash/wm/system_gesture_event_filter.cc b/ash/wm/system_gesture_event_filter.cc
index 69bcc55..f935fd8c 100644
--- a/ash/wm/system_gesture_event_filter.cc
+++ b/ash/wm/system_gesture_event_filter.cc
@@ -24,11 +24,6 @@
           ui::TouchScreensAvailability::ENABLED) {
     base::RecordAction(base::UserMetricsAction("Mouse_Down"));
   }
-
-  if (event->IsMouseWheelEvent() && wm_gesture_handler_ &&
-      wm_gesture_handler_->ProcessWheelEvent(*event)) {
-    event->StopPropagation();
-  }
 }
 
 void SystemGestureEventFilter::OnScrollEvent(ui::ScrollEvent* event) {
diff --git a/ash/wm/window_cycle/window_cycle_controller_unittest.cc b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
index 1aeccbc..b7e812d 100644
--- a/ash/wm/window_cycle/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "ash/frame_throttler/mock_frame_throttling_observer.h"
 #include "ash/home_screen/home_screen_controller.h"
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/session/session_controller_impl.h"
@@ -26,13 +27,18 @@
 #include "ash/wm/desks/desk.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/desks/desks_test_util.h"
+#include "ash/wm/gestures/wm_gesture_handler.h"
+#include "ash/wm/overview/overview_controller.h"
+#include "ash/wm/overview/overview_test_util.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
+#include "ash/wm/window_cycle/window_cycle_event_filter.h"
 #include "ash/wm/window_cycle/window_cycle_list.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "components/prefs/pref_service.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/env.h"
@@ -52,6 +58,9 @@
 
 namespace {
 
+constexpr int kNumFingersForMouseWheel = 2;
+constexpr int kNumFingersForTrackpad = 3;
+
 class EventCounter : public ui::EventHandler {
  public:
   EventCounter() : key_events_(0), mouse_events_(0) {}
@@ -84,6 +93,37 @@
   return WindowState::Get(window)->IsMinimized();
 }
 
+bool InOverviewSession() {
+  return Shell::Get()->overview_controller()->InOverviewSession();
+}
+
+const aura::Window* GetHighlightedWindow() {
+  return InOverviewSession() ? GetOverviewHighlightedWindow() : nullptr;
+}
+
+bool IsNaturalScrollOn() {
+  PrefService* pref =
+      Shell::Get()->session_controller()->GetActivePrefService();
+  return pref->GetBoolean(prefs::kTouchpadEnabled) &&
+         pref->GetBoolean(prefs::kNaturalScroll);
+}
+
+int GetOffsetX(int offset) {
+  // The handler code uses the new directions which is the reverse of the old
+  // handler code. Reverse the offset if the ReverseScrollGestures feature is
+  // disabled so that the unit tests test the old behavior.
+  return features::IsReverseScrollGesturesEnabled() ? offset : -offset;
+}
+
+int GetOffsetY(int offset) {
+  // The handler code uses the new directions which is the reverse of the old
+  // handler code. Reverse the offset if the ReverseScrollGestures feature is
+  // disabled so that the unit tests test the old behavior.
+  if (!features::IsReverseScrollGesturesEnabled() || IsNaturalScrollOn())
+    return -offset;
+  return offset;
+}
+
 }  // namespace
 
 using aura::Window;
@@ -906,6 +946,75 @@
   }
 }
 
+// Tests that frame throttling starts and ends accordingly when window cycling
+// starts and ends.
+TEST_F(WindowCycleControllerTest, FrameThrottling) {
+  MockFrameThrottlingObserver observer;
+  FrameThrottlingController* frame_throttling_controller =
+      Shell::Get()->frame_throttling_controller();
+  uint8_t throttled_fps = frame_throttling_controller->throttled_fps();
+  frame_throttling_controller->AddObserver(&observer);
+  const int window_count = 5;
+  std::unique_ptr<aura::Window> created_windows[window_count];
+  std::vector<aura::Window*> windows(window_count, nullptr);
+  for (int i = 0; i < window_count; ++i) {
+    created_windows[i] = CreateAppWindow(gfx::Rect(), AppType::BROWSER);
+    windows[i] = created_windows[i].get();
+  }
+
+  WindowCycleController* controller = Shell::Get()->window_cycle_controller();
+  EXPECT_CALL(observer,
+              OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
+                                  throttled_fps));
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_CALL(observer,
+              OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
+                                  throttled_fps))
+      .Times(0);
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_CALL(observer, OnThrottlingEnded());
+  controller->CompleteCycling();
+
+  EXPECT_CALL(observer,
+              OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
+                                  throttled_fps));
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_CALL(observer, OnThrottlingEnded());
+  controller->CancelCycling();
+  frame_throttling_controller->RemoveObserver(&observer);
+}
+
+// Tests that pressing Alt+Tab while there is an on-going desk animation
+// prevents a new window cycle from starting.
+TEST_F(WindowCycleControllerTest, DoubleAltTabWithDeskSwitch) {
+  WindowCycleController* cycle_controller =
+      Shell::Get()->window_cycle_controller();
+
+  auto win0 = CreateAppWindow(gfx::Rect(250, 100));
+  auto* desks_controller = DesksController::Get();
+  desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
+  ASSERT_EQ(2u, desks_controller->desks().size());
+  const Desk* desk_0 = desks_controller->desks()[0].get();
+  const Desk* desk_1 = desks_controller->desks()[1].get();
+  ActivateDesk(desk_1);
+  EXPECT_EQ(desk_1, desks_controller->active_desk());
+  auto win1 = CreateAppWindow(gfx::Rect(300, 200));
+  ASSERT_EQ(win1.get(), window_util::GetActiveWindow());
+  auto desk_1_windows = desk_1->windows();
+  EXPECT_EQ(1u, desk_1_windows.size());
+  EXPECT_TRUE(base::Contains(desk_1_windows, win1.get()));
+
+  DeskSwitchAnimationWaiter waiter;
+  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  cycle_controller->CompleteCycling();
+  EXPECT_FALSE(cycle_controller->CanCycle());
+  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_FALSE(cycle_controller->IsCycling());
+  waiter.Wait();
+  EXPECT_EQ(desk_0, desks_controller->active_desk());
+  EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
+}
+
 class LimitedWindowCycleControllerTest : public WindowCycleControllerTest {
  public:
   LimitedWindowCycleControllerTest() = default;
@@ -1004,6 +1113,18 @@
     WindowCycleControllerTest::SetUp();
   }
 
+  void Scroll(float x_offset, float y_offset, int fingers) {
+    GetEventGenerator()->ScrollSequence(
+        gfx::Point(), base::TimeDelta::FromMilliseconds(5),
+        GetOffsetX(x_offset), GetOffsetY(y_offset), /*steps=*/100, fingers);
+  }
+
+  void MouseWheelScroll(int delta_x, int delta_y, int num_of_times) {
+    auto* generator = GetEventGenerator();
+    for (int i = 0; i < num_of_times; i++)
+      generator->MoveMouseWheel(delta_x, delta_y);
+  }
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
@@ -1284,73 +1405,302 @@
   EXPECT_LT(0, event_count.GetMouseEventCountAndReset());
 }
 
-// Tests that frame throttling starts and ends accordingly when window cycling
-// starts and ends.
-TEST_F(WindowCycleControllerTest, FrameThrottling) {
-  MockFrameThrottlingObserver observer;
-  FrameThrottlingController* frame_throttling_controller =
-      Shell::Get()->frame_throttling_controller();
-  uint8_t throttled_fps = frame_throttling_controller->throttled_fps();
-  frame_throttling_controller->AddObserver(&observer);
-  const int window_count = 5;
-  std::unique_ptr<aura::Window> created_windows[window_count];
-  std::vector<aura::Window*> windows(window_count, nullptr);
-  for (int i = 0; i < window_count; ++i) {
-    created_windows[i] = CreateAppWindow(gfx::Rect(), AppType::BROWSER);
-    windows[i] = created_windows[i].get();
-  }
+// Tests three finger horizontal scroll gesture to move selection left or right.
+TEST_F(InteractiveWindowCycleControllerTest,
+       ThreeFingerHorizontalScrollInWindowCycleList) {
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
+  const float horizontal_scroll =
+      WindowCycleEventFilter::kHorizontalThresholdDp;
 
-  WindowCycleController* controller = Shell::Get()->window_cycle_controller();
-  EXPECT_CALL(observer,
-              OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
-                                  throttled_fps));
-  controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_CALL(observer,
-              OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
-                                  throttled_fps))
-      .Times(0);
-  controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_CALL(observer, OnThrottlingEnded());
-  controller->CompleteCycling();
+  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
+                                                            float y_offset) {
+    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
+    controller->StartCycling();
+    Scroll(GetOffsetX(x_offset), GetOffsetY(y_offset), kNumFingersForTrackpad);
+    controller->CompleteCycling();
+  };
 
-  EXPECT_CALL(observer,
-              OnThrottlingStarted(testing::UnorderedElementsAreArray(windows),
-                                  throttled_fps));
-  controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_CALL(observer, OnThrottlingEnded());
-  controller->CancelCycling();
-  frame_throttling_controller->RemoveObserver(&observer);
+  // Start cycle, simulating alt key being held down. Scroll right to fourth
+  // item.
+  // Current order is [5,4,3,2,1].
+  scroll_until_window_highlighted_and_confirm(horizontal_scroll * 3, 0);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  // Start cycle. Scroll left to third item.
+  // Current order is [2,5,4,3,1].
+  scroll_until_window_highlighted_and_confirm(-horizontal_scroll * 3, 0);
+  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
+
+  // Start cycle. Scroll right to second item.
+  // Current order is [4,2,5,3,1].
+  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  // Open an overview session and window cycle list. Scroll right to second
+  // item. Scroll should only go to the window cycle list.
+  // Current order is [2,4,5,3,1].
+  Shell::Get()->overview_controller()->StartOverview();
+  EXPECT_TRUE(InOverviewSession());
+
+  Shell::Get()->window_cycle_controller()->StartCycling();
+  Scroll(GetOffsetX(horizontal_scroll), 0, kNumFingersForTrackpad);
+  EXPECT_EQ(nullptr, GetHighlightedWindow());
+
+  Shell::Get()->window_cycle_controller()->CompleteCycling();
+  EXPECT_FALSE(InOverviewSession());
+  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
 }
 
-// Tests that pressing Alt+Tab while there is an on-going desk animation
-// prevents a new window cycle from starting.
-TEST_F(WindowCycleControllerTest, DoubleAltTabWithDeskSwitch) {
-  WindowCycleController* cycle_controller =
-      Shell::Get()->window_cycle_controller();
+// Tests two finger horizontal scroll gesture to move selection left or right.
+TEST_F(InteractiveWindowCycleControllerTest,
+       TwoFingerHorizontalScrollInWindowCycleList) {
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
+  const float horizontal_scroll =
+      WindowCycleEventFilter::kHorizontalThresholdDp;
 
-  auto win0 = CreateAppWindow(gfx::Rect(250, 100));
-  auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
-  ASSERT_EQ(2u, desks_controller->desks().size());
-  const Desk* desk_0 = desks_controller->desks()[0].get();
-  const Desk* desk_1 = desks_controller->desks()[1].get();
-  ActivateDesk(desk_1);
-  EXPECT_EQ(desk_1, desks_controller->active_desk());
-  auto win1 = CreateAppWindow(gfx::Rect(300, 200));
-  ASSERT_EQ(win1.get(), window_util::GetActiveWindow());
-  auto desk_1_windows = desk_1->windows();
-  EXPECT_EQ(1u, desk_1_windows.size());
-  EXPECT_TRUE(base::Contains(desk_1_windows, win1.get()));
+  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
+                                                            float y_offset) {
+    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
+    controller->StartCycling();
+    // Since two finger swipes are negated, negate in tests to mimic how this
+    // actually behaves on devices.
+    Scroll(GetOffsetX(-x_offset), GetOffsetY(y_offset),
+           kNumFingersForMouseWheel);
+    controller->CompleteCycling();
+  };
 
-  DeskSwitchAnimationWaiter waiter;
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  cycle_controller->CompleteCycling();
-  EXPECT_FALSE(cycle_controller->CanCycle());
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_FALSE(cycle_controller->IsCycling());
-  waiter.Wait();
-  EXPECT_EQ(desk_0, desks_controller->active_desk());
-  EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
+  // Start cycle, simulating alt key being held down. Scroll right to fourth
+  // item.
+  // Current order is [5,4,3,2,1].
+  scroll_until_window_highlighted_and_confirm(horizontal_scroll * 3, 0);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  // Start cycle. Scroll left to third item.
+  // Current order is [2,5,4,3,1].
+  scroll_until_window_highlighted_and_confirm(-horizontal_scroll * 3, 0);
+  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
+
+  // Start cycle. Scroll right to second item.
+  // Current order is [4,2,5,3,1].
+  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+}
+
+// Tests mouse wheel scroll gesture to move selection left or right.
+TEST_F(InteractiveWindowCycleControllerTest,
+       MouseWheelScrollInWindowCycleList) {
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
+  const float horizontal_scroll =
+      WindowCycleEventFilter::kHorizontalThresholdDp;
+
+  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
+                                                            float y_offset,
+                                                            int num_of_times) {
+    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
+    controller->StartCycling();
+    MouseWheelScroll(x_offset, y_offset, num_of_times);
+    controller->CompleteCycling();
+  };
+
+  // Start cycle, simulating alt key being held down. Scroll right to fourth
+  // item.
+  // Current order is [5,4,3,2,1].
+  scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 3);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  // Start cycle. Scroll left to third item.
+  // Current order is [2,5,4,3,1].
+  scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 3);
+  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
+
+  // Start cycle. Scroll right to second item.
+  // Current order is [4,2,5,3,1].
+  scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 1);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+}
+
+// Tests that swiping up closes window cycle if it's open and starts overview
+// mode.
+TEST_F(InteractiveWindowCycleControllerTest, VerticalScroll) {
+  std::unique_ptr<aura::Window> window1 = CreateTestWindow();
+  std::unique_ptr<aura::Window> window2 = CreateTestWindow();
+  const float vertical_scroll = 2 * WmGestureHandler::kVerticalThresholdDp;
+  const float horizontal_scroll =
+      WindowCycleEventFilter::kHorizontalThresholdDp;
+  auto* window_cycle_controller = Shell::Get()->window_cycle_controller();
+
+  // Start cycling and then swipe up to open up overview.
+  window_cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(window_cycle_controller->IsCycling());
+  Scroll(0, vertical_scroll, 3);
+  EXPECT_TRUE(InOverviewSession());
+  EXPECT_FALSE(window_cycle_controller->IsCycling());
+
+  // Start cycling and then swipe down.
+  window_cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(window_cycle_controller->IsCycling());
+  Scroll(0, -vertical_scroll, 3);
+  EXPECT_TRUE(window_cycle_controller->IsCycling());
+
+  // Swipe diagonally with horizontal bias.
+  Scroll(horizontal_scroll * 3, vertical_scroll, 3);
+  EXPECT_TRUE(window_cycle_controller->IsCycling());
+  EXPECT_FALSE(InOverviewSession());
+
+  // Swipe diagonally with vertical bias.
+  Scroll(horizontal_scroll, vertical_scroll, 3);
+  EXPECT_FALSE(window_cycle_controller->IsCycling());
+  EXPECT_TRUE(InOverviewSession());
+}
+
+class ReverseGestureWindowCycleControllerTest
+    : public InteractiveWindowCycleControllerTest {
+ public:
+  ReverseGestureWindowCycleControllerTest() = default;
+  ReverseGestureWindowCycleControllerTest(
+      const ReverseGestureWindowCycleControllerTest&) = delete;
+  ReverseGestureWindowCycleControllerTest& operator=(
+      const ReverseGestureWindowCycleControllerTest&) = delete;
+  ~ReverseGestureWindowCycleControllerTest() override = default;
+
+  // AshTestBase:
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(features::kReverseScrollGestures);
+    AshTestBase::SetUp();
+
+    // Set natural scroll on.
+    PrefService* pref =
+        Shell::Get()->session_controller()->GetActivePrefService();
+    pref->SetBoolean(prefs::kTouchpadEnabled, true);
+    pref->SetBoolean(prefs::kNaturalScroll, true);
+    pref->SetBoolean(prefs::kMouseReverseScroll, true);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Tests mouse wheel scroll gesture to move selection left or right. Mouse
+// reverse scroll should reverse its direction.
+TEST_F(ReverseGestureWindowCycleControllerTest,
+       MouseWheelScrollInWindowCycleList) {
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
+  const float horizontal_scroll =
+      WindowCycleEventFilter::kHorizontalThresholdDp;
+
+  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
+                                                            float y_offset,
+                                                            int num_of_times) {
+    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
+    controller->StartCycling();
+    MouseWheelScroll(x_offset, y_offset, num_of_times);
+    controller->CompleteCycling();
+  };
+
+  // Start cycle, simulating alt key being held down. Scroll right to fourth
+  // item.
+  // Current order is [5,4,3,2,1].
+  scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 3);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  // Start cycle. Scroll left to third item.
+  // Current order is [2,5,4,3,1].
+  scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 3);
+  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
+
+  // Start cycle. Scroll right to second item.
+  // Current order is [4,2,5,3,1].
+  scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 1);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  // Turn mouse reverse scroll off.
+  PrefService* pref =
+      Shell::Get()->session_controller()->GetActivePrefService();
+  pref->SetBoolean(prefs::kMouseReverseScroll, false);
+
+  // Start cycle. Scroll left once.
+  // Current order is [2,4,5,3,1].
+  scroll_until_window_highlighted_and_confirm(0, horizontal_scroll, 1);
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
+
+  // Start cycle. Scroll right once.
+  // Current order is [1,2,4,5,3].
+  scroll_until_window_highlighted_and_confirm(0, -horizontal_scroll, 1);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+}
+
+// Tests that natural scroll doesn't affect two and three finger horizontal
+// scroll gestures for cycling window cycle list.
+TEST_F(ReverseGestureWindowCycleControllerTest,
+       WindowCycleListTrackpadGestures) {
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds);
+  std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds);
+  const float horizontal_scroll =
+      WindowCycleEventFilter::kHorizontalThresholdDp;
+
+  auto scroll_until_window_highlighted_and_confirm = [this](float x_offset,
+                                                            float y_offset,
+                                                            int num_fingers) {
+    WindowCycleController* controller = Shell::Get()->window_cycle_controller();
+    controller->StartCycling();
+    Scroll(x_offset, y_offset, num_fingers);
+    controller->CompleteCycling();
+  };
+
+  // Start cycle, scroll right with two finger gesture.
+  // Current order is [5,4,3,2,1].
+  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
+                                              kNumFingersForMouseWheel);
+  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
+
+  // Start cycle, scroll right with three finger gesture.
+  // Current order is [4,5,3,2,1].
+  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
+                                              kNumFingersForTrackpad);
+  EXPECT_TRUE(wm::IsActiveWindow(window5.get()));
+
+  // Turn natural scroll off.
+  PrefService* pref =
+      Shell::Get()->session_controller()->GetActivePrefService();
+  pref->SetBoolean(prefs::kNaturalScroll, false);
+
+  // Start cycle, scroll right with two finger gesture. Note: two figner swipes
+  // are negated, so negate in tests to mimic how this actually behaves on
+  // devices.
+  // Current order is [5,4,3,2,1].
+  scroll_until_window_highlighted_and_confirm(-horizontal_scroll, 0,
+                                              kNumFingersForMouseWheel);
+  EXPECT_TRUE(wm::IsActiveWindow(window4.get()));
+
+  // Start cycle, scroll right with three finger gesture.
+  // Current order is [4,5,3,2,1].
+  scroll_until_window_highlighted_and_confirm(horizontal_scroll, 0,
+                                              kNumFingersForTrackpad);
+  EXPECT_TRUE(wm::IsActiveWindow(window5.get()));
 }
 
 class ModeSelectionWindowCycleControllerTest
diff --git a/ash/wm/window_cycle/window_cycle_event_filter.cc b/ash/wm/window_cycle/window_cycle_event_filter.cc
index 84ef3df..33ade20 100644
--- a/ash/wm/window_cycle/window_cycle_event_filter.cc
+++ b/ash/wm/window_cycle/window_cycle_event_filter.cc
@@ -7,11 +7,15 @@
 #include "ash/accelerators/debug_commands.h"
 #include "ash/display/screen_ash.h"
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/ash_pref_names.h"
+#include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/wm/window_cycle/window_cycle_controller.h"
 #include "ash/wm/window_cycle/window_cycle_list.h"
 #include "base/bind.h"
+#include "components/prefs/pref_service.h"
 #include "ui/events/event.h"
+#include "ui/events/types/event_type.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
 namespace ash {
@@ -20,6 +24,21 @@
 // before this stops filtering mouse events.
 constexpr int kMouseMovementThreshold = 5;
 
+// Is the reverse scrolling for touchpad on.
+bool IsNaturalScrollOn() {
+  PrefService* pref =
+      Shell::Get()->session_controller()->GetActivePrefService();
+  return pref->GetBoolean(prefs::kTouchpadEnabled) &&
+         pref->GetBoolean(prefs::kNaturalScroll);
+}
+
+// Is reverse scrolling for mouse wheel on.
+bool IsReverseScrollOn() {
+  PrefService* pref =
+      Shell::Get()->session_controller()->GetActivePrefService();
+  return pref->GetBoolean(prefs::kMouseReverseScroll);
+}
+
 WindowCycleEventFilter::WindowCycleEventFilter()
     : initial_mouse_location_(
           display::Screen::GetScreen()->GetCursorScreenPoint()) {
@@ -117,6 +136,87 @@
   }
 }
 
+void WindowCycleEventFilter::ProcessMouseEvent(ui::MouseEvent* event) {
+  auto* window_cycle_controller = Shell::Get()->window_cycle_controller();
+  if (event->type() == ui::ET_MOUSE_PRESSED &&
+      !window_cycle_controller->IsEventInCycleView(event)) {
+    // Close the window cycle list if a user clicks outside of it.
+    window_cycle_controller->CancelCycling();
+    return;
+  }
+
+  if (event->IsMouseWheelEvent()) {
+    if (!scroll_data_)
+      scroll_data_ = ScrollData();
+    const ui::MouseWheelEvent* wheel_event = event->AsMouseWheelEvent();
+    const float y_offset = wheel_event->y_offset();
+    // Convert mouse wheel events into three-finger scrolls for window cycle
+    // list and also swap y offset with x offset.
+    if (ProcessEventImpl(/*finger_count=*/3,
+                         IsReverseScrollOn() ? y_offset : -y_offset,
+                         wheel_event->x_offset())) {
+      event->SetHandled();
+      event->StopPropagation();
+    }
+  }
+}
+
+bool WindowCycleEventFilter::ProcessEventImpl(int finger_count,
+                                              float delta_x,
+                                              float delta_y) {
+  if (!scroll_data_ || !features::IsInteractiveWindowCycleListEnabled())
+    return false;
+
+  if (finger_count != 2 && finger_count != 3) {
+    scroll_data_.reset();
+    return false;
+  }
+
+  if (scroll_data_->finger_count != 0 &&
+      scroll_data_->finger_count != finger_count) {
+    scroll_data_.reset();
+    return false;
+  }
+
+  if (finger_count == 2 && !IsNaturalScrollOn()) {
+    // Two finger swipe from left to right should move the list right regardless
+    // of natural scroll settings.
+    delta_x = -delta_x;
+  }
+
+  scroll_data_->scroll_x += delta_x;
+  scroll_data_->scroll_y += delta_y;
+
+  const bool moved = CycleWindowCycleList(finger_count, scroll_data_->scroll_x,
+                                          scroll_data_->scroll_y);
+
+  if (moved)
+    scroll_data_ = ScrollData();
+  scroll_data_->finger_count = finger_count;
+  return moved;
+}
+
+bool WindowCycleEventFilter::CycleWindowCycleList(int finger_count,
+                                                  float scroll_x,
+                                                  float scroll_y) {
+  if (!features::IsInteractiveWindowCycleListEnabled() ||
+      (finger_count != 2 && finger_count != 3)) {
+    return false;
+  }
+
+  auto* window_cycle_controller = Shell::Get()->window_cycle_controller();
+  if (!window_cycle_controller->IsCycling() ||
+      std::fabs(scroll_x) < std::fabs(scroll_y) ||
+      std::fabs(scroll_x) < kHorizontalThresholdDp) {
+    return false;
+  }
+
+  window_cycle_controller->HandleCycleWindow(
+      scroll_x > 0 ? WindowCycleController::FORWARD
+                   : WindowCycleController::BACKWARD);
+  return true;
+}
+
 WindowCycleController::Direction WindowCycleEventFilter::GetDirection(
     ui::KeyEvent* event) const {
   DCHECK(IsTriggerKey(event));
@@ -134,19 +234,17 @@
   if (!has_user_used_mouse_)
     SetHasUserUsedMouse(event);
 
-  if (features::IsInteractiveWindowCycleListEnabled()) {
+  if (features::IsInteractiveWindowCycleListEnabled() && has_user_used_mouse_) {
     WindowCycleController* window_cycle_controller =
         Shell::Get()->window_cycle_controller();
     const bool cycle_list_is_visible =
         window_cycle_controller->IsWindowListVisible();
-    const bool event_should_not_be_filtered =
-        has_user_used_mouse_ &&
-        window_cycle_controller->IsEventInCycleView(event);
-    if (event_should_not_be_filtered || !cycle_list_is_visible) {
+    if (cycle_list_is_visible)
+      ProcessMouseEvent(event);
+
+    if (window_cycle_controller->IsEventInCycleView(event) ||
+        !cycle_list_is_visible) {
       return;
-    } else if (event->type() == ui::ET_MOUSE_PRESSED && cycle_list_is_visible) {
-      // Close the window cycle list if a user clicks outside of it.
-      window_cycle_controller->CancelCycling();
     }
   }
 
@@ -159,6 +257,28 @@
   }
 }
 
+void WindowCycleEventFilter::OnScrollEvent(ui::ScrollEvent* event) {
+  // ET_SCROLL_FLING_CANCEL means a touchpad swipe has started.
+  if (event->type() == ui::ET_SCROLL_FLING_CANCEL) {
+    scroll_data_ = ScrollData();
+    return;
+  }
+
+  // ET_SCROLL_FLING_START means a touchpad swipe has ended.
+  if (event->type() == ui::ET_SCROLL_FLING_START) {
+    scroll_data_.reset();
+    return;
+  }
+
+  DCHECK_EQ(ui::ET_SCROLL, event->type());
+
+  if (ProcessEventImpl(event->finger_count(), event->x_offset(),
+                       event->y_offset())) {
+    event->SetHandled();
+    event->StopPropagation();
+  }
+}
+
 void WindowCycleEventFilter::OnGestureEvent(ui::GestureEvent* event) {
   if (features::IsInteractiveWindowCycleListEnabled() &&
       Shell::Get()->window_cycle_controller()->IsEventInCycleView(event)) {
diff --git a/ash/wm/window_cycle/window_cycle_event_filter.h b/ash/wm/window_cycle/window_cycle_event_filter.h
index 6ba936606..668d709 100644
--- a/ash/wm/window_cycle/window_cycle_event_filter.h
+++ b/ash/wm/window_cycle/window_cycle_event_filter.h
@@ -8,10 +8,18 @@
 #include "ash/ash_export.h"
 #include "ash/wm/window_cycle/window_cycle_controller.h"
 #include "base/macros.h"
+#include "base/optional.h"
 #include "base/timer/timer.h"
 #include "ui/events/event_handler.h"
 #include "ui/gfx/geometry/point.h"
 
+namespace ui {
+class GestureEvent;
+class KeyEvent;
+class MouseEvent;
+class ScrollEvent;
+}  // namespace ui
+
 namespace ash {
 
 // Created by WindowCycleController when cycling through windows. Eats all key
@@ -19,15 +27,30 @@
 // Also allows users to cycle using right/left keys.
 class ASH_EXPORT WindowCycleEventFilter : public ui::EventHandler {
  public:
+  // The threshold of performing an action with a touchpad or mouse wheel
+  // scroll.
+  static constexpr float kHorizontalThresholdDp = 330.f;
+
   WindowCycleEventFilter();
   ~WindowCycleEventFilter() override;
 
   // Overridden from ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* event) override;
   void OnMouseEvent(ui::MouseEvent* event) override;
+  void OnScrollEvent(ui::ScrollEvent* event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
 
  private:
+  // A struct containing the relevant data during a scroll session.
+  struct ScrollData {
+    int finger_count = 0;
+
+    // Values are cumulative (ex. |scroll_x| is the total x distance moved
+    // since the scroll began.
+    float scroll_x = 0.f;
+    float scroll_y = 0.f;
+  };
+
   class AltReleaseHandler : public ui::EventHandler {
    public:
     AltReleaseHandler();
@@ -59,6 +82,20 @@
   // clicked.
   void SetHasUserUsedMouse(ui::MouseEvent* event);
 
+  // Depending on the properties of |event|, may cycle the window cycle list or
+  // complete cycling.
+  void ProcessMouseEvent(ui::MouseEvent* event);
+
+  // Called by ProcessMouseEvent() and OnScrollEvent(). May cycle the window
+  // cycle list. Returns true if the event has been handled and should not be
+  // processed further, false otherwise.
+  bool ProcessEventImpl(int finger_count, float delta_x, float delta_y);
+
+  // Based on the given scroll data, determine whether we should cycle the
+  // window cycle list. Return true if we do cycle the window cycle list,
+  // otherwise return false.
+  bool CycleWindowCycleList(int finger_count, float scroll_x, float scroll_y);
+
   // Returns the direction the window cycle should cycle depending on the
   // combination of keys being pressed.
   WindowCycleController::Direction GetDirection(ui::KeyEvent* event) const;
@@ -83,6 +120,10 @@
   // See crbug.com/114375.
   bool has_user_used_mouse_ = false;
 
+  // Stores the current scroll session data. If it does not exist, there is no
+  // active scroll session.
+  base::Optional<ScrollData> scroll_data_;
+
   DISALLOW_COPY_AND_ASSIGN(WindowCycleEventFilter);
 };
 
diff --git a/base/system/sys_info.cc b/base/system/sys_info.cc
index 281c283..8a77b3a 100644
--- a/base/system/sys_info.cc
+++ b/base/system/sys_info.cc
@@ -17,7 +17,6 @@
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
-#include "base/task_runner_util.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -92,16 +91,7 @@
 #endif
 
 void SysInfo::GetHardwareInfo(base::OnceCallback<void(HardwareInfo)> callback) {
-#if defined(OS_WIN)
-  // On Windows the calls to GetHardwareInfoSync can take a really long time to
-  // complete as they depend on WMI, using the CONTINUE_ON_SHUTDOWN traits will
-  // prevent this task from blocking shutdown.
-  base::PostTaskAndReplyWithResult(
-      base::ThreadPool::CreateCOMSTATaskRunner(
-          {TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})
-          .get(),
-      FROM_HERE, base::BindOnce(&GetHardwareInfoSync), std::move(callback));
-#elif defined(OS_ANDROID) || defined(OS_APPLE)
+#if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_APPLE)
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {}, base::BindOnce(&GetHardwareInfoSync), std::move(callback));
 #elif defined(OS_LINUX) || defined(OS_CHROMEOS)
diff --git a/base/system/sys_info.h b/base/system/sys_info.h
index 61df0adf..9ee81b0 100644
--- a/base/system/sys_info.h
+++ b/base/system/sys_info.h
@@ -85,16 +85,6 @@
   struct HardwareInfo {
     std::string manufacturer;
     std::string model;
-    // On Windows, this is the BIOS serial number. Unsupported platforms will be
-    // set to an empty string.
-    // Note: validate any new usage with the privacy team.
-    // TODO(crbug.com/907518): Implement support on other platforms.
-    std::string serial_number;
-
-    bool operator==(const HardwareInfo& rhs) const {
-      return manufacturer == rhs.manufacturer && model == rhs.model &&
-             serial_number == rhs.serial_number;
-    }
   };
   // Returns via |callback| a struct containing descriptive UTF-8 strings for
   // the current machine manufacturer and model, or empty strings if the
diff --git a/base/system/sys_info_unittest.cc b/base/system/sys_info_unittest.cc
index e44745c..fbd4483c 100644
--- a/base/system/sys_info_unittest.cc
+++ b/base/system/sys_info_unittest.cc
@@ -16,12 +16,22 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
 #include "base/test/scoped_chromeos_version_info.h"
 #include "base/test/scoped_running_on_chromeos.h"
 #include "base/test/task_environment.h"
 #include "base/threading/platform_thread.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
+#if defined(OS_WIN)
+#include "base/win/com_init_util.h"
+#include "base/win/scoped_bstr.h"
+#include "base/win/scoped_com_initializer.h"
+#include "base/win/scoped_variant.h"
+#include "base/win/wmi.h"
+#endif  // defined(OS_WIN)
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "testing/gtest/include/gtest/gtest-death-test.h"
@@ -207,14 +217,63 @@
 #endif
   EXPECT_EQ(hardware_info->manufacturer.empty(), empty_result_expected);
   EXPECT_EQ(hardware_info->model.empty(), empty_result_expected);
+}
 
 #if defined(OS_WIN)
-  EXPECT_FALSE(hardware_info->serial_number.empty());
-#else
-  // TODO(crbug.com/907518): Implement support on other platforms.
-  EXPECT_EQ(hardware_info->serial_number, std::string());
-#endif
+TEST_F(SysInfoTest, GetHardwareInfoWMIMatchRegistry) {
+  base::win::ScopedCOMInitializer com_initializer;
+  test::TaskEnvironment task_environment;
+  base::Optional<SysInfo::HardwareInfo> hardware_info;
+
+  auto callback = base::BindOnce(
+      [](base::Optional<SysInfo::HardwareInfo>* target_info,
+         SysInfo::HardwareInfo info) { *target_info = std::move(info); },
+      &hardware_info);
+  SysInfo::GetHardwareInfo(std::move(callback));
+  task_environment.RunUntilIdle();
+
+  ASSERT_TRUE(hardware_info.has_value());
+
+  Microsoft::WRL::ComPtr<IWbemServices> wmi_services;
+  EXPECT_TRUE(base::win::CreateLocalWmiConnection(true, &wmi_services));
+
+  static constexpr wchar_t query_computer_system[] =
+      L"SELECT Manufacturer,Model FROM Win32_ComputerSystem";
+
+  Microsoft::WRL::ComPtr<IEnumWbemClassObject> enumerator_computer_system;
+  HRESULT hr = wmi_services->ExecQuery(
+      base::win::ScopedBstr(L"WQL").Get(),
+      base::win::ScopedBstr(query_computer_system).Get(),
+      WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
+      &enumerator_computer_system);
+  EXPECT_FALSE(FAILED(hr) || !enumerator_computer_system.Get());
+
+  Microsoft::WRL::ComPtr<IWbemClassObject> class_object;
+  ULONG items_returned = 0;
+  hr = enumerator_computer_system->Next(WBEM_INFINITE, 1, &class_object,
+                                        &items_returned);
+  EXPECT_FALSE(FAILED(hr) || !items_returned);
+
+  base::win::ScopedVariant manufacturerVar;
+  std::wstring manufacturer;
+  hr = class_object->Get(L"Manufacturer", 0, manufacturerVar.Receive(), nullptr,
+                         nullptr);
+  if (SUCCEEDED(hr) && manufacturerVar.type() == VT_BSTR) {
+    manufacturer.assign(V_BSTR(manufacturerVar.ptr()),
+                        ::SysStringLen(V_BSTR(manufacturerVar.ptr())));
+  }
+  base::win::ScopedVariant modelVar;
+  std::wstring model;
+  hr = class_object->Get(L"Model", 0, modelVar.Receive(), nullptr, nullptr);
+  if (SUCCEEDED(hr) && modelVar.type() == VT_BSTR) {
+    model.assign(V_BSTR(modelVar.ptr()),
+                 ::SysStringLen(V_BSTR(modelVar.ptr())));
+  }
+
+  EXPECT_TRUE(hardware_info->manufacturer == base::SysWideToUTF8(manufacturer));
+  EXPECT_TRUE(hardware_info->model == base::SysWideToUTF8(model));
 }
+#endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
 
diff --git a/base/system/sys_info_win.cc b/base/system/sys_info_win.cc
index 685e593..119cef1 100644
--- a/base/system/sys_info_win.cc
+++ b/base/system/sys_info_win.cc
@@ -16,10 +16,11 @@
 #include "base/process/process_metrics.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/scoped_blocking_call.h"
+#include "base/win/registry.h"
 #include "base/win/windows_version.h"
-#include "base/win/wmi.h"
 
 namespace {
 
@@ -168,15 +169,26 @@
 
 // static
 SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() {
-  win::WmiComputerSystemInfo wmi_info = win::WmiComputerSystemInfo::Get();
+  constexpr base::char16 kSystemBiosInformationRegKey[] =
+      L"HARDWARE\\DESCRIPTION\\System\\BIOS";
 
   HardwareInfo info;
-  info.manufacturer = WideToUTF8(wmi_info.manufacturer());
-  info.model = WideToUTF8(wmi_info.model());
-  info.serial_number = WideToUTF8(wmi_info.serial_number());
-  DCHECK(IsStringUTF8(info.manufacturer));
-  DCHECK(IsStringUTF8(info.model));
-  DCHECK(IsStringUTF8(info.serial_number));
+  base::win::RegKey system_information_key;
+  if (system_information_key.Open(HKEY_LOCAL_MACHINE,
+                                  kSystemBiosInformationRegKey,
+                                  KEY_READ) == ERROR_SUCCESS) {
+    base::string16 value16;
+    if (system_information_key.ReadValue(L"SystemManufacturer", &value16) ==
+        ERROR_SUCCESS) {
+      info.manufacturer = base::SysWideToUTF8(value16);
+    }
+
+    if (system_information_key.ReadValue(L"SystemProductName", &value16) ==
+        ERROR_SUCCESS) {
+      info.model = base::SysWideToUTF8(value16);
+    }
+  }
+
   return info;
 }
 
diff --git a/base/win/wmi.cc b/base/win/wmi.cc
index 8153079b..9f2c0246 100644
--- a/base/win/wmi.cc
+++ b/base/win/wmi.cc
@@ -143,46 +143,11 @@
   if (!CreateLocalWmiConnection(true, &services))
     return info;
 
-  info.PopulateModelAndManufacturer(services);
   info.PopulateSerialNumber(services);
 
   return info;
 }
 
-void WmiComputerSystemInfo::PopulateModelAndManufacturer(
-    const ComPtr<IWbemServices>& services) {
-  static constexpr WStringPiece query_computer_system =
-      L"SELECT Manufacturer,Model FROM Win32_ComputerSystem";
-
-  ComPtr<IEnumWbemClassObject> enumerator_computer_system;
-  HRESULT hr = services->ExecQuery(
-      ScopedBstr(L"WQL").Get(), ScopedBstr(query_computer_system).Get(),
-      WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
-      &enumerator_computer_system);
-  if (FAILED(hr) || !enumerator_computer_system.Get())
-    return;
-
-  ComPtr<IWbemClassObject> class_object;
-  ULONG items_returned = 0;
-  hr = enumerator_computer_system->Next(WBEM_INFINITE, 1, &class_object,
-                                        &items_returned);
-  if (FAILED(hr) || !items_returned)
-    return;
-
-  ScopedVariant manufacturer;
-  hr = class_object->Get(L"Manufacturer", 0, manufacturer.Receive(), nullptr,
-                         nullptr);
-  if (SUCCEEDED(hr) && manufacturer.type() == VT_BSTR) {
-    manufacturer_.assign(V_BSTR(manufacturer.ptr()),
-                         ::SysStringLen(V_BSTR(manufacturer.ptr())));
-  }
-  ScopedVariant model;
-  hr = class_object->Get(L"Model", 0, model.Receive(), nullptr, nullptr);
-  if (SUCCEEDED(hr) && model.type() == VT_BSTR) {
-    model_.assign(V_BSTR(model.ptr()), ::SysStringLen(V_BSTR(model.ptr())));
-  }
-}
-
 void WmiComputerSystemInfo::PopulateSerialNumber(
     const ComPtr<IWbemServices>& services) {
   static constexpr WStringPiece query_bios =
diff --git a/base/win/wmi.h b/base/win/wmi.h
index 7949888a..08a29bc 100644
--- a/base/win/wmi.h
+++ b/base/win/wmi.h
@@ -67,22 +67,19 @@
 // 'Win32_Bios' WMI classes; see :
 // https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-computersystem
 // https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-systembios
+// Note that while model and manufacturer can be obtained through WMI, it is
+// more efficient to obtain them via SysInfo::GetHardwareInfo() which uses the
+// registry.
 class BASE_EXPORT WmiComputerSystemInfo {
  public:
   static WmiComputerSystemInfo Get();
 
-  const std::wstring& manufacturer() const { return manufacturer_; }
-  const std::wstring& model() const { return model_; }
   const std::wstring& serial_number() const { return serial_number_; }
 
  private:
-  void PopulateModelAndManufacturer(
-      const Microsoft::WRL::ComPtr<IWbemServices>& services);
   void PopulateSerialNumber(
       const Microsoft::WRL::ComPtr<IWbemServices>& services);
 
-  std::wstring manufacturer_;
-  std::wstring model_;
   std::wstring serial_number_;
 };
 
diff --git a/base/win/wmi_unittest.cc b/base/win/wmi_unittest.cc
index 51637f3d..7a6f66bb 100644
--- a/base/win/wmi_unittest.cc
+++ b/base/win/wmi_unittest.cc
@@ -59,8 +59,7 @@
 
 TEST_F(WMITest, TestComputerSystemInfo) {
   WmiComputerSystemInfo info = WmiComputerSystemInfo::Get();
-  EXPECT_FALSE(info.manufacturer().empty());
-  EXPECT_FALSE(info.model().empty());
+  EXPECT_FALSE(info.serial_number().empty());
 }
 
 }  // namespace win
diff --git a/cc/input/threaded_input_handler.cc b/cc/input/threaded_input_handler.cc
index cd33cfe..3ff2adb 100644
--- a/cc/input/threaded_input_handler.cc
+++ b/cc/input/threaded_input_handler.cc
@@ -1842,6 +1842,7 @@
                                                   ui::ScrollInputType type) {
   ScrollTree& scroll_tree = GetScrollTree();
   ScrollNode* scroll_node = nullptr;
+  ScrollNode* first_scrollable_node = nullptr;
   for (ScrollNode* cur_node = starting_node; cur_node;
        cur_node = scroll_tree.parent(cur_node)) {
     if (GetViewport().ShouldScroll(*cur_node)) {
@@ -1855,10 +1856,11 @@
     if (!cur_node->scrollable)
       continue;
 
-    // For UX reasons, autoscrolling should always latch to the top-most
-    // scroller, even if it can't scroll in the initial direction.
-    if (type == ui::ScrollInputType::kAutoscroll ||
-        CanConsumeDelta(*scroll_state, *cur_node)) {
+    if (!first_scrollable_node) {
+      first_scrollable_node = cur_node;
+    }
+
+    if (CanConsumeDelta(*scroll_state, *cur_node)) {
       scroll_node = cur_node;
       break;
     }
@@ -1880,6 +1882,13 @@
     }
   }
 
+  // If the root scroller can not consume delta in an autoscroll, latch on
+  // to the top most autoscrollable scroller. See https://crbug.com/969150
+  if ((type == ui::ScrollInputType::kAutoscroll) && first_scrollable_node &&
+      !CanConsumeDelta(*scroll_state, *scroll_node)) {
+    scroll_node = first_scrollable_node;
+  }
+
   return scroll_node;
 }
 
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index abd434e..61596a3 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -227,7 +227,7 @@
     "//components/strings:components_strings_grd",
     "//components/subresource_filter/android:java_resources",
     "//components/translate/content/android:java_resources",
-    "//components/webapps/android:java_resources",
+    "//components/webapps/browser/android:java_resources",
     "//content/public/android:content_java_resources",
     "//third_party/android_data_chart:android_data_chart_java_resources",
     "//third_party/android_deps:android_support_v7_appcompat_java",
@@ -473,7 +473,7 @@
     "//components/viz/service:service_java",
     "//components/webapk/android/libs/client:java",
     "//components/webapk/android/libs/common:java",
-    "//components/webapps/android:java",
+    "//components/webapps/browser/android:java",
     "//components/webrtc/android:java",
     "//components/webxr/android:ar_java_interfaces",
     "//content/public/android:content_java",
@@ -926,7 +926,7 @@
     "//components/version_info/android:version_constants_java",
     "//components/webapk/android/libs/client:java",
     "//components/webapk/android/libs/common:java",
-    "//components/webapps/android:java",
+    "//components/webapps/browser/android:java",
     "//content/public/android:content_java",
     "//content/public/test/android:content_java_test_support",
     "//mojo/public/java:bindings_java",
@@ -1226,7 +1226,7 @@
     "//components/url_formatter/android:url_formatter_javatests",
     "//components/user_prefs/android:java",
     "//components/webapk/android/libs/client:java",
-    "//components/webapps/android:java",
+    "//components/webapps/browser/android:java",
     "//content/public/android:content_java",
     "//content/public/test/android:content_java_test_support",
     "//media/base/android:java_switches",
diff --git a/chrome/android/DEPS b/chrome/android/DEPS
index 086730b..efc50d6f0 100644
--- a/chrome/android/DEPS
+++ b/chrome/android/DEPS
@@ -74,7 +74,7 @@
   "+components/user_prefs/android",
   "+components/viz/common/java",
   "+components/webapk/android",
-  "+components/webapps/android/java",
+  "+components/webapps/browser/android/java",
   "+components/webrtc/android",
   "+jni",
   "+media/base/android/java",
diff --git a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
index 75cd67f..43cf49c6 100644
--- a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
@@ -1,5 +1,6 @@
 <?xml version="1.0" ?>
 <manifest
+    android:isolatedSplits="true"
     package="org.chromium.chrome.stable"
     platformBuildVersionCode="30"
     platformBuildVersionName="11"
@@ -72,13 +73,14 @@
   <application
       android:allowAudioPlaybackCapture="false"
       android:allowBackup="false"
+      android:appComponentFactory="org.chromium.chrome.browser.base.SplitCompatAppComponentFactory"
       android:extractNativeLibs="false"
       android:icon="@drawable/ic_launcher"
       android:label="@string/app_name"
       android:largeHeap="false"
       android:manageSpaceActivity="@string/manage_space_activity"
       android:multiArch="true"
-      android:name="org.chromium.chrome.browser.MonochromeApplication"
+      android:name="org.chromium.chrome.browser.base.SplitMonochromeApplication"
       android:networkSecurityConfig="@xml/network_security_config"
       android:roundIcon="@drawable/ic_launcher_round"
       android:supportsRtl="true"
diff --git a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
index b041668..3842e6c 100644
--- a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
@@ -250,6 +250,17 @@
 # and 53kb memory/process (through shrinking method/string counts).
 -repackageclasses ''
 
+# File: ../../chrome/android/proguard/isolated_splits.flags
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Isolated splits currently use DexSplitter for splitting out some DFMs.
+# DexSplitter has some issues with certain R8 optimizations, so we need to keep
+# ModuleInterface classes to make sure they aren't inlined.
+-keep @interface org.chromium.components.module_installer.builder.ModuleInterface
+-keep @org.chromium.components.module_installer.builder.ModuleInterface class ** {}
+
 # File: ../../chrome/android/proguard/main.flags
 # Copyright 2016 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
diff --git a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
index 5d1710dc..8e83eef 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
@@ -1,5 +1,6 @@
 <?xml version="1.0" ?>
 <manifest
+    android:isolatedSplits="true"
     package="org.chromium.chrome.stable"
     platformBuildVersionCode="30"
     platformBuildVersionName="11"
@@ -72,13 +73,14 @@
   <application
       android:allowAudioPlaybackCapture="false"
       android:allowBackup="false"
+      android:appComponentFactory="org.chromium.chrome.browser.base.SplitCompatAppComponentFactory"
       android:extractNativeLibs="false"
       android:icon="@drawable/ic_launcher"
       android:label="@string/app_name"
       android:largeHeap="false"
       android:manageSpaceActivity="@string/manage_space_activity"
       android:multiArch="true"
-      android:name="org.chromium.chrome.browser.ChromeApplication"
+      android:name="org.chromium.chrome.browser.base.SplitChromeApplication"
       android:networkSecurityConfig="@xml/network_security_config"
       android:roundIcon="@drawable/ic_launcher_round"
       android:supportsRtl="true"
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index df8b221..49b9ffa 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -125,9 +125,9 @@
     "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantChipViewHolder.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/ButtonView.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java",
+    "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsAdapter.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java",
-    "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantPlaceholdersConfiguration.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/details/ImageClickthroughData.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/form/AssistantFormCoordinator.java",
@@ -357,6 +357,7 @@
     "java/res/drawable/autofill_assistant_circle_background.xml",
     "java/res/drawable/autofill_assistant_default_details.xml",
     "java/res/drawable/autofill_assistant_details_bg.xml",
+    "java/res/drawable/autofill_assistant_details_list_divider.xml",
     "java/res/drawable/autofill_assistant_lightblue_rect_bg.xml",
     "java/res/drawable/autofill_assistant_rounded_corner_background.xml",
     "java/res/drawable/autofill_assistant_swipe_indicator.xml",
diff --git a/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_details_bg.xml b/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_details_bg.xml
index aff6ec185..7438f2f 100644
--- a/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_details_bg.xml
+++ b/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_details_bg.xml
@@ -7,6 +7,6 @@
     android:shape="rectangle">
   <corners android:radius="8dp" />
   <stroke
-      android:color="@color/default_chip_outline_color"
+      android:color="@color/autofill_assistant_details_divider_color"
       android:width="1dp" />
 </shape>
diff --git a/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_details_list_divider.xml b/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_details_list_divider.xml
new file mode 100644
index 0000000..56c7ae9
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/java/res/drawable/autofill_assistant_details_list_divider.xml
@@ -0,0 +1,9 @@
+<!-- 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. -->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <size android:height="1dp" />
+    <solid android:color="@color/autofill_assistant_details_divider_color" />
+</shape>
\ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_details.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_details.xml
index 45531f0..d2f6dcea 100644
--- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_details.xml
+++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_details.xml
@@ -7,9 +7,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/autofill_assistant_details_bg"
     android:padding="16dp"
-    android:visibility="gone"
     android:orientation="vertical">
     <LinearLayout android:layout_width="match_parent"
                   android:layout_height="wrap_content"
diff --git a/chrome/android/features/autofill_assistant/java/res/values-v17/colors.xml b/chrome/android/features/autofill_assistant/java/res/values-v17/colors.xml
index 69940d5d..56c401a 100644
--- a/chrome/android/features/autofill_assistant/java/res/values-v17/colors.xml
+++ b/chrome/android/features/autofill_assistant/java/res/values-v17/colors.xml
@@ -11,4 +11,5 @@
     -->
     <color name="autofill_assistant_light_blue">@color/modern_blue_600_alpha_10</color>
     <color name="autofill_assistant_actions_shadow_color">@color/modern_grey_100</color>
+    <color name="autofill_assistant_details_divider_color">@color/default_chip_outline_color</color>
 </resources>
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
index c48ebc8..e2a03baa 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -32,6 +32,8 @@
 import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataCoordinator;
 import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel;
+import org.chromium.chrome.browser.image_fetcher.ImageFetcherConfig;
+import org.chromium.chrome.browser.image_fetcher.ImageFetcherFactory;
 import org.chromium.chrome.browser.ui.TabObscuringHandler;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
@@ -143,7 +145,9 @@
         // Instantiate child components.
         mHeaderCoordinator = new AssistantHeaderCoordinator(activity, model.getHeaderModel());
         mInfoBoxCoordinator = new AssistantInfoBoxCoordinator(activity, model.getInfoBoxModel());
-        mDetailsCoordinator = new AssistantDetailsCoordinator(activity, model.getDetailsModel());
+        mDetailsCoordinator = new AssistantDetailsCoordinator(activity, model.getDetailsModel(),
+                ImageFetcherFactory.createImageFetcher(ImageFetcherConfig.DISK_CACHE_ONLY,
+                        AutofillAssistantUiController.getProfile()));
         mPaymentRequestCoordinator =
                 new AssistantCollectUserDataCoordinator(activity, model.getCollectUserDataModel());
         mFormCoordinator = new AssistantFormCoordinator(activity, model.getFormModel());
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsAdapter.java
similarity index 82%
rename from chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java
rename to chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsAdapter.java
index a82e65c..70839bf 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsViewBinder.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsAdapter.java
@@ -27,12 +27,16 @@
 import android.widget.TextView;
 
 import androidx.annotation.StyleRes;
+import androidx.core.content.res.ResourcesCompat;
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.RecyclerView;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.autofill_assistant.AssistantTextUtils;
+import org.chromium.chrome.browser.autofill_assistant.LayoutUtils;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.image_fetcher.ImageFetcher;
 import org.chromium.components.browser_ui.modaldialog.AppModalPresenter;
@@ -41,25 +45,24 @@
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
- * This class is responsible for pushing updates to the Autofill Assistant details view. These
- * updates are pulled from the {@link AssistantDetailsModel} when a notification of an update is
- * received.
+ * This class is responsible for binding details to their associated view.
  */
-class AssistantDetailsViewBinder
-        implements PropertyModelChangeProcessor.ViewBinder<AssistantDetailsModel,
-                AssistantDetailsViewBinder.ViewHolder, PropertyKey> {
+class AssistantDetailsAdapter extends RecyclerView.Adapter<AssistantDetailsAdapter.ViewHolder> {
+    private final List<AssistantDetails> mDetails = new ArrayList<>();
+
     private static final int IMAGE_BORDER_RADIUS = 8;
     private static final int PULSING_DURATION_MS = 1_000;
 
     /**
      * A wrapper class that holds the different views of the header.
      */
-    static class ViewHolder {
+    static class ViewHolder extends RecyclerView.ViewHolder {
         final GradientDrawable mDefaultImage;
         final ImageView mImageView;
         final TextView mTitleView;
@@ -72,8 +75,10 @@
         final TextView mTotalPriceView;
 
         ViewHolder(Context context, View detailsView) {
-            mDefaultImage = (GradientDrawable) context.getResources().getDrawable(
-                    R.drawable.autofill_assistant_default_details);
+            super(detailsView);
+
+            mDefaultImage = (GradientDrawable) ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.autofill_assistant_default_details, /* theme= */ null);
             mImageView = detailsView.findViewById(R.id.details_image);
             mTitleView = detailsView.findViewById(R.id.details_title);
             mDescriptionLine1View = detailsView.findViewById(R.id.details_line1);
@@ -98,7 +103,7 @@
     private ValueAnimator mPulseAnimation;
     private ImageFetcher mImageFetcher;
 
-    AssistantDetailsViewBinder(Context context, ImageFetcher imageFetcher) {
+    AssistantDetailsAdapter(Context context, ImageFetcher imageFetcher) {
         mContext = context;
         mImageWidth = context.getResources().getDimensionPixelSize(
                 R.dimen.autofill_assistant_details_image_size);
@@ -121,22 +126,70 @@
         mImageFetcher = null;
     }
 
-    @Override
-    public void bind(AssistantDetailsModel model, ViewHolder view, PropertyKey propertyKey) {
-        if (AssistantDetailsModel.DETAILS == propertyKey) {
-            AssistantDetails details = model.get(AssistantDetailsModel.DETAILS);
-            if (details == null) {
-                // Handled by the AssistantDetailsCoordinator.
-                return;
+    /** Set the details. */
+    void setDetails(List<AssistantDetails> details) {
+        // Compute the diff.
+        int oldSize = mDetails.size();
+        int newSize = details.size();
+        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() {
+            @Override
+            public int getOldListSize() {
+                return oldSize;
             }
 
-            setDetails(details, view);
-        } else {
-            assert false : "Unhandled property detected in AssistantDetailsViewBinder!";
-        }
+            @Override
+            public int getNewListSize() {
+                return newSize;
+            }
+
+            @Override
+            public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+                // Assume that oldList[i] == newList[j] only if i == j, to minimize the number of
+                // add/remove animations when replacing or appending details.
+                return oldItemPosition == newItemPosition;
+            }
+
+            @Override
+            public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+                // Assume contents are never the same, that way we always update each details view.
+                return false;
+            }
+
+            @Override
+            public Object getChangePayload(int oldItemPosition, int newItemPosition) {
+                // We need to return a non-null payload, otherwise the whole details view will
+                // fade-out then fade-in when changing.
+                return details.get(newItemPosition);
+            }
+        }, /* detectMoves= */ false);
+
+        // Set the details.
+        mDetails.clear();
+        mDetails.addAll(details);
+
+        // Notify the change.
+        diffResult.dispatchUpdatesTo(this);
     }
 
-    private void setDetails(AssistantDetails details, ViewHolder viewHolder) {
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+        Context context = viewGroup.getContext();
+        View detailsView = LayoutUtils.createInflater(context).inflate(
+                R.layout.autofill_assistant_details, viewGroup, /* attachToRoot= */ false);
+        return new ViewHolder(context, detailsView);
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder viewHolder, int i) {
+        bindDetails(mDetails.get(i), viewHolder);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mDetails.size();
+    }
+
+    private void bindDetails(AssistantDetails details, ViewHolder viewHolder) {
         AssistantTextUtils.applyVisualAppearanceTags(
                 viewHolder.mTitleView, details.getTitle(), null);
         AssistantTextUtils.applyVisualAppearanceTags(
@@ -208,20 +261,19 @@
             // Download image and then set it in the view.
             ImageFetcher.Params params = ImageFetcher.Params.create(
                     details.getImageUrl(), ImageFetcher.ASSISTANT_DETAILS_UMA_CLIENT_NAME);
-            mImageFetcher.fetchImage(
-                    params, image -> {
-                        if (image != null) {
-                            viewHolder.mImageView.setImageDrawable(getRoundedImage(image));
-                            if (details.hasImageClickthroughData()
-                                    && details.getImageClickthroughData().getAllowClickthrough()) {
-                                viewHolder.mImageView.setOnClickListener(unusedView
-                                        -> onImageClicked(mContext, details.getImageUrl(),
-                                                details.getImageClickthroughData()));
-                            } else {
-                                viewHolder.mImageView.setOnClickListener(null);
-                            }
-                        }
-                    });
+            mImageFetcher.fetchImage(params, image -> {
+                if (image != null) {
+                    viewHolder.mImageView.setImageDrawable(getRoundedImage(image));
+                    if (details.hasImageClickthroughData()
+                            && details.getImageClickthroughData().getAllowClickthrough()) {
+                        viewHolder.mImageView.setOnClickListener(unusedView
+                                -> onImageClicked(mContext, details.getImageUrl(),
+                                        details.getImageClickthroughData()));
+                    } else {
+                        viewHolder.mImageView.setOnClickListener(null);
+                    }
+                }
+            });
         }
 
         setTextStyles(details, viewHolder);
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java
index eeeb4e7..a45645e 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsCoordinator.java
@@ -5,70 +5,89 @@
 package org.chromium.chrome.browser.autofill_assistant.details;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.view.View;
+import android.view.ViewGroup;
 
-import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.content.res.AppCompatResources;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
 
 import org.chromium.chrome.autofill_assistant.R;
-import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiController;
-import org.chromium.chrome.browser.autofill_assistant.LayoutUtils;
-import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsViewBinder.ViewHolder;
 import org.chromium.chrome.browser.image_fetcher.ImageFetcher;
-import org.chromium.chrome.browser.image_fetcher.ImageFetcherConfig;
-import org.chromium.chrome.browser.image_fetcher.ImageFetcherFactory;
-import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
 /**
  * Coordinator responsible for showing details.
  */
 public class AssistantDetailsCoordinator {
-    private final View mView;
-    private final AssistantDetailsModel mModel;
+    private final RecyclerView mView;
 
-    public AssistantDetailsCoordinator(Context context, AssistantDetailsModel model) {
-        this(context, model,
-                ImageFetcherFactory.createImageFetcher(ImageFetcherConfig.DISK_CACHE_ONLY,
-                        AutofillAssistantUiController.getProfile()));
-    }
-
-    @VisibleForTesting
     public AssistantDetailsCoordinator(
             Context context, AssistantDetailsModel model, ImageFetcher imageFetcher) {
-        mView = LayoutUtils.createInflater(context).inflate(
-                R.layout.autofill_assistant_details, /* root= */ null);
-        mModel = model;
-        ViewHolder viewHolder = new ViewHolder(context, mView);
-        AssistantDetailsViewBinder viewBinder =
-                new AssistantDetailsViewBinder(context, imageFetcher);
-        PropertyModelChangeProcessor.create(model, viewHolder, viewBinder);
+        mView = new RecyclerView(context);
+        mView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+        mView.setLayoutManager(new LinearLayoutManager(
+                context, LinearLayoutManager.VERTICAL, /* reverseLayout= */ false));
+        mView.setBackgroundResource(R.drawable.autofill_assistant_details_bg);
+        mView.addItemDecoration(new DetailsItemDecoration(context));
+        AssistantDetailsAdapter adapter = new AssistantDetailsAdapter(context, imageFetcher);
+        mView.setAdapter(adapter);
 
-        // Details view is initially hidden.
-        updateVisibility();
-
-        // Observe details in model to hide or show this coordinator view.
+        // Listen to the model and set the details on the adapter when they change.
         model.addObserver((source, propertyKey) -> {
-            if (AssistantDetailsModel.DETAILS == propertyKey) {
-                updateVisibility();
+            if (propertyKey == AssistantDetailsModel.DETAILS) {
+                adapter.setDetails(model.get(AssistantDetailsModel.DETAILS));
+            }
+        });
+
+        // Observe the details and make this coordinator's view visible only if the details contain
+        // at least one item. That way its margins (set by the AssistantBottomBar Coordinator) will
+        // be considered during layout only if there is at least one details to show.
+        mView.setVisibility(View.GONE);
+        model.addObserver((source, propertyKey) -> {
+            if (propertyKey == AssistantDetailsModel.DETAILS) {
+                int visibility = model.get(AssistantDetailsModel.DETAILS).size() > 0 ? View.VISIBLE
+                                                                                     : View.GONE;
+                if (mView.getVisibility() != visibility) {
+                    mView.setVisibility(visibility);
+                }
             }
         });
     }
 
-    /**
-     * Return the view associated to the details.
-     */
-    public View getView() {
+    public RecyclerView getView() {
         return mView;
     }
 
-    /**
-     * Show or hide the details within its parent and call the {@code mOnVisibilityChanged}
-     * listener.
-     */
-    private void updateVisibility() {
-        int visibility =
-                mModel.get(AssistantDetailsModel.DETAILS) != null ? View.VISIBLE : View.GONE;
-        if (mView.getVisibility() != visibility) {
-            mView.setVisibility(visibility);
+    /** A divider that is drawn after each details, except the last one. */
+    private static class DetailsItemDecoration extends RecyclerView.ItemDecoration {
+        private final Drawable mDrawable;
+        private final Rect mBounds = new Rect();
+
+        public DetailsItemDecoration(Context context) {
+            mDrawable = AppCompatResources.getDrawable(
+                    context, R.drawable.autofill_assistant_details_list_divider);
+        }
+
+        @Override
+        public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
+            // Note: this implementation is inspired from DividerItemDecoration#drawVertical.
+            int left = parent.getPaddingLeft();
+            int right = parent.getWidth() - parent.getPaddingRight();
+            int childCount = parent.getChildCount();
+
+            // Draw a divider after each child, except the last one.
+            for (int i = 0; i < childCount - 1; ++i) {
+                View child = parent.getChildAt(i);
+                parent.getDecoratedBoundsWithMargins(child, this.mBounds);
+                int bottom = this.mBounds.bottom + Math.round(child.getTranslationY());
+                int top = bottom - this.mDrawable.getIntrinsicHeight();
+                this.mDrawable.setBounds(left, top, right, bottom);
+                this.mDrawable.draw(canvas);
+            }
         }
     }
 }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java
index 13655f0e..a89f546 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java
@@ -4,12 +4,15 @@
 
 package org.chromium.chrome.browser.autofill_assistant.details;
 
-import androidx.annotation.VisibleForTesting;
+import android.support.annotation.VisibleForTesting;
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * State for the details of the Autofill Assistant.
  */
@@ -18,21 +21,27 @@
     // TODO(crbug.com/806868): We might want to split this property into multiple, simpler
     // properties.
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
-    public static final WritableObjectPropertyKey<AssistantDetails> DETAILS =
+    public static final WritableObjectPropertyKey<List<AssistantDetails>> DETAILS =
             new WritableObjectPropertyKey<>();
 
     public AssistantDetailsModel() {
         super(DETAILS);
+        set(DETAILS, new ArrayList<>());
     }
 
     @CalledByNative
-    private void setDetails(AssistantDetails details) {
-        set(DETAILS, details);
+    private static List<AssistantDetails> createDetailsList() {
+        return new ArrayList<>();
     }
 
     @CalledByNative
-    // TODO(crbug.com/806868): Make private once this is only called by native.
-    public void clearDetails() {
-        set(DETAILS, null);
+    private static void addDetails(List<AssistantDetails> list, AssistantDetails details) {
+        list.add(details);
+    }
+
+    @CalledByNative
+    @VisibleForTesting
+    public void setDetailsList(List<AssistantDetails> list) {
+        set(DETAILS, list);
     }
 }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDetailsUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDetailsUiTest.java
index c77c01f..e5fdc597 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDetailsUiTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDetailsUiTest.java
@@ -10,14 +10,15 @@
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
+import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.nullValue;
 
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.hasTypefaceSpan;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.hasTypefaceStyle;
@@ -30,11 +31,10 @@
 import android.graphics.Typeface;
 import android.support.test.InstrumentationRegistry;
 import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
 
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matcher;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -50,6 +50,8 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 
+import java.util.Arrays;
+
 /** Tests for the Autofill Assistant details. */
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @RunWith(ChromeJUnit4ClassRunner.class)
@@ -65,27 +67,39 @@
     @Rule
     public CustomTabActivityTestRule mTestRule = new CustomTabActivityTestRule();
 
-    private static class ViewHolder {
-        final ImageView mImageView;
-        final TextView mTitleView;
-        final TextView mDescriptionLine1View;
-        final TextView mDescriptionLine2View;
-        final TextView mDescriptionLine3View;
-        final TextView mPriceAttributionView;
-        final View mPriceView;
-        final TextView mTotalPriceLabelView;
-        final TextView mTotalPriceView;
+    /**
+     * Matchers for the different views of a single details item in the details list. We need to use
+     * matchers (instead of directly querying with findViewById) because the inflation of the
+     * details views if postponed to the UI-thread when adding items to the list, so we can't assume
+     * that the details views are available directly after adding items to the details list.
+     */
+    private static class ViewMatchers {
+        final Matcher<View> mImageView;
+        final Matcher<View> mTitleView;
+        final Matcher<View> mDescriptionLine1View;
+        final Matcher<View> mDescriptionLine2View;
+        final Matcher<View> mDescriptionLine3View;
+        final Matcher<View> mPriceAttributionView;
+        final Matcher<View> mPriceView;
+        final Matcher<View> mTotalPriceLabelView;
+        final Matcher<View> mTotalPriceView;
 
-        ViewHolder(View detailsView) {
-            mImageView = detailsView.findViewById(R.id.details_image);
-            mTitleView = detailsView.findViewById(R.id.details_title);
-            mDescriptionLine1View = detailsView.findViewById(R.id.details_line1);
-            mDescriptionLine2View = detailsView.findViewById(R.id.details_line2);
-            mDescriptionLine3View = detailsView.findViewById(R.id.details_line3);
-            mPriceAttributionView = detailsView.findViewById(R.id.details_price_attribution);
-            mPriceView = detailsView.findViewById(R.id.details_price);
-            mTotalPriceView = detailsView.findViewById(R.id.details_total_price);
-            mTotalPriceLabelView = detailsView.findViewById(R.id.details_total_price_label);
+        ViewMatchers(View detailsListView) {
+            mImageView = descendantWithId(detailsListView, R.id.details_image);
+            mTitleView = descendantWithId(detailsListView, R.id.details_title);
+            mDescriptionLine1View = descendantWithId(detailsListView, R.id.details_line1);
+            mDescriptionLine2View = descendantWithId(detailsListView, R.id.details_line2);
+            mDescriptionLine3View = descendantWithId(detailsListView, R.id.details_line3);
+            mPriceAttributionView =
+                    descendantWithId(detailsListView, R.id.details_price_attribution);
+            mPriceView = descendantWithId(detailsListView, R.id.details_price);
+            mTotalPriceView = descendantWithId(detailsListView, R.id.details_total_price);
+            mTotalPriceLabelView =
+                    descendantWithId(detailsListView, R.id.details_total_price_label);
+        }
+
+        private Matcher<View> descendantWithId(View ancestor, int id) {
+            return allOf(isDescendantOfA(is(ancestor)), withId(id));
         }
     }
 
@@ -106,6 +120,10 @@
         return coordinator;
     }
 
+    private static void setDetails(AssistantDetailsModel model, AssistantDetails... details) {
+        runOnUiThreadBlocking(() -> model.setDetailsList(Arrays.asList(details)));
+    }
+
     @Before
     public void setUp() {
         AutofillAssistantUiTestUtil.startOnBlankPage(mTestRule);
@@ -118,8 +136,8 @@
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
 
-        assertThat(model.get(AssistantDetailsModel.DETAILS), nullValue());
-        onView(is(coordinator.getView())).check(matches(not(isDisplayed())));
+        assertThat(model.get(AssistantDetailsModel.DETAILS).size(), is(0));
+        assertThat(coordinator.getView().getChildCount(), is(0));
     }
 
     /** Tests visibility of views. */
@@ -128,24 +146,22 @@
     public void testVisibility() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
-        runOnUiThreadBlocking(() -> {
-            model.set(AssistantDetailsModel.DETAILS,
-                    new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
-                            "line 2", "", "line 3", false, false, false, false, false,
-                            NO_PLACEHOLDERS));
-        });
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
+                        "line 2", "", "line 3", false, false, false, false, false,
+                        NO_PLACEHOLDERS));
 
-        onView(is(viewHolder.mImageView)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mTitleView)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mDescriptionLine1View)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mDescriptionLine2View)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mDescriptionLine3View)).check(matches(not(isDisplayed())));
-        onView(is(viewHolder.mPriceView)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mTotalPriceLabelView)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mTotalPriceView)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mPriceAttributionView)).check(matches(isDisplayed()));
+        onView(viewMatchers.mImageView).check(matches(isDisplayed()));
+        onView(viewMatchers.mTitleView).check(matches(isDisplayed()));
+        onView(viewMatchers.mDescriptionLine1View).check(matches(isDisplayed()));
+        onView(viewMatchers.mDescriptionLine2View).check(matches(isDisplayed()));
+        onView(viewMatchers.mDescriptionLine3View).check(matches(not(isDisplayed())));
+        onView(viewMatchers.mPriceView).check(matches(isDisplayed()));
+        onView(viewMatchers.mTotalPriceLabelView).check(matches(isDisplayed()));
+        onView(viewMatchers.mTotalPriceView).check(matches(isDisplayed()));
+        onView(viewMatchers.mPriceAttributionView).check(matches(isDisplayed()));
     }
 
     @Test
@@ -153,17 +169,15 @@
     public void testAccessibility() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
-        runOnUiThreadBlocking(() -> {
-            model.set(AssistantDetailsModel.DETAILS,
-                    new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
-                            "line 2", "", "line 3", false, false, false, false, false,
-                            NO_PLACEHOLDERS));
-        });
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
+                        "line 2", "", "line 3", false, false, false, false, false,
+                        NO_PLACEHOLDERS));
 
-        onView(is(viewHolder.mImageView)).check(matches(withContentDescription("hint")));
-        onView(is(viewHolder.mImageView))
+        onView(viewMatchers.mImageView).check(matches(withContentDescription("hint")));
+        onView(viewMatchers.mImageView)
                 .check(matches(isImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_AUTO)));
     }
 
@@ -172,17 +186,14 @@
     public void testAccessibilityEmpty() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
-        runOnUiThreadBlocking(() -> {
-            model.set(AssistantDetailsModel.DETAILS,
-                    new AssistantDetails("title", "image", "", null, "Total", "$12", "line 1",
-                            "line 2", "", "line 3", false, false, false, false, false,
-                            NO_PLACEHOLDERS));
-        });
+        setDetails(model,
+                new AssistantDetails("title", "image", "", null, "Total", "$12", "line 1", "line 2",
+                        "", "line 3", false, false, false, false, false, NO_PLACEHOLDERS));
 
-        onView(is(viewHolder.mImageView)).check(matches(withContentDescription("")));
-        onView(is(viewHolder.mImageView))
+        onView(viewMatchers.mImageView).check(matches(withContentDescription("")));
+        onView(viewMatchers.mImageView)
                 .check(matches(isImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO)));
     }
 
@@ -191,75 +202,59 @@
     public void testTitle() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
         /* Description lines 1 and 2 are set, title must be in single line. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "line 1", "line 2", "", "price", false, false, false, false,
-                                        false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView)).check(matches(isTextMaxLines(1)));
-        onView(is(viewHolder.mTitleView)).check(matches(allOf(withText("title"), isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
+                        "line 2", "", "price", false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(1)));
+        onView(viewMatchers.mTitleView).check(matches(allOf(withText("title"), isDisplayed())));
 
         /* Description line 1 is set, title must be max 2 lines. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "line 1", "", "", "price", false, false, false, false,
-                                        false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView)).check(matches(isTextMaxLines(2)));
-        onView(is(viewHolder.mTitleView)).check(matches(allOf(withText("title"), isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1", "",
+                        "", "price", false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(2)));
+        onView(viewMatchers.mTitleView).check(matches(allOf(withText("title"), isDisplayed())));
 
         /* Description line 2 is set, title must be max 2 lines. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "", "line 2", "", "price", false, false, false, false,
-                                        false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView)).check(matches(isTextMaxLines(2)));
-        onView(is(viewHolder.mTitleView)).check(matches(allOf(withText("title"), isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "line 2",
+                        "", "price", false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(2)));
+        onView(viewMatchers.mTitleView).check(matches(allOf(withText("title"), isDisplayed())));
 
         /* None of description line 1 or 2 is set, title must be max 3 lines. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "", "", "", "price", false, false, false, false, false,
-                                        NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView)).check(matches(isTextMaxLines(3)));
-        onView(is(viewHolder.mTitleView)).check(matches(allOf(withText("title"), isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "", "",
+                        "price", false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(3)));
+        onView(viewMatchers.mTitleView).check(matches(allOf(withText("title"), isDisplayed())));
 
         /* There is a placeholder for description line 1, title must be max 2 lines. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "", "", "", "price", false, false, false, false, false,
-                                        new AssistantPlaceholdersConfiguration(
-                                                /* showImagePlaceholder= */ false,
-                                                /* showTitlePlaceholder= */ false,
-                                                /* showDescriptionLine1Placeholder= */ true,
-                                                /* showDescriptionLine2Placeholder= */ false,
-                                                /* showDescriptionLine3Placeholder= */ false))));
-        onView(is(viewHolder.mTitleView)).check(matches(isTextMaxLines(2)));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "", "",
+                        "price", false, false, false, false, false,
+                        new AssistantPlaceholdersConfiguration(
+                                /* showImagePlaceholder= */ false,
+                                /* showTitlePlaceholder= */ false,
+                                /* showDescriptionLine1Placeholder= */ true,
+                                /* showDescriptionLine2Placeholder= */ false,
+                                /* showDescriptionLine3Placeholder= */ false)));
+        onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(2)));
 
         /* There is a placeholder for description line 1 & 2, title must be max 1 line. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "", "", "", "price", false, false, false, false, false,
-                                        new AssistantPlaceholdersConfiguration(
-                                                /* showImagePlaceholder= */ false,
-                                                /* showTitlePlaceholder= */ false,
-                                                /* showDescriptionLine1Placeholder= */ true,
-                                                /* showDescriptionLine2Placeholder= */ true,
-                                                /* showDescriptionLine3Placeholder= */ false))));
-        onView(is(viewHolder.mTitleView)).check(matches(isTextMaxLines(1)));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "", "",
+                        "price", false, false, false, false, false,
+                        new AssistantPlaceholdersConfiguration(
+                                /* showImagePlaceholder= */ false,
+                                /* showTitlePlaceholder= */ false,
+                                /* showDescriptionLine1Placeholder= */ true,
+                                /* showDescriptionLine2Placeholder= */ true,
+                                /* showDescriptionLine3Placeholder= */ false)));
+        onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(1)));
     }
 
     @Test
@@ -267,24 +262,20 @@
     public void testDescriptionLine1() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
         /* Description line 1 is set and should be visible. */
-        runOnUiThreadBlocking(()
-                                      -> model.set(AssistantDetailsModel.DETAILS,
-                                              new AssistantDetails("title", "image", "hint", null,
-                                                      "", "", "line 1", "", "", "", false, false,
-                                                      false, false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mDescriptionLine1View))
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "", "", "line 1", "", "", "",
+                        false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mDescriptionLine1View)
                 .check(matches(allOf(withText("line 1"), isDisplayed())));
 
         /* Description line 1 is not set and should be invisible. */
-        runOnUiThreadBlocking(()
-                                      -> model.set(AssistantDetailsModel.DETAILS,
-                                              new AssistantDetails("title", "image", "hint", null,
-                                                      "", "", "", "", "", "", false, false, false,
-                                                      false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mDescriptionLine1View)).check(matches(not(isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "", "", "", "", "", "", false,
+                        false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mDescriptionLine1View).check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -292,24 +283,20 @@
     public void testDescriptionLine2() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
         /* Description line 2 is set and should be visible. */
-        runOnUiThreadBlocking(()
-                                      -> model.set(AssistantDetailsModel.DETAILS,
-                                              new AssistantDetails("title", "image", "hint", null,
-                                                      "", "", "", "line 2", "", "", false, false,
-                                                      false, false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mDescriptionLine2View))
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "", "", "", "line 2", "", "",
+                        false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mDescriptionLine2View)
                 .check(matches(allOf(withText("line 2"), isDisplayed())));
 
         /* Description line 2 is not set and should be invisible. */
-        runOnUiThreadBlocking(()
-                                      -> model.set(AssistantDetailsModel.DETAILS,
-                                              new AssistantDetails("title", "image", "hint", null,
-                                                      "", "", "", "", "", "", false, false, false,
-                                                      false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mDescriptionLine2View)).check(matches(not(isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "", "", "", "", "", "", false,
+                        false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mDescriptionLine2View).check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -317,24 +304,20 @@
     public void testDescriptionLine3() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
         /* Description line 3 is set and should be visible. */
-        runOnUiThreadBlocking(()
-                                      -> model.set(AssistantDetailsModel.DETAILS,
-                                              new AssistantDetails("title", "image", "hint", null,
-                                                      "", "", "", "", "line 3", "", false, false,
-                                                      false, false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mDescriptionLine3View))
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "", "", "", "", "line 3", "",
+                        false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mDescriptionLine3View)
                 .check(matches(allOf(withText("line 3"), isDisplayed())));
 
         /* Description line 3 is not set and should be invisible. */
-        runOnUiThreadBlocking(()
-                                      -> model.set(AssistantDetailsModel.DETAILS,
-                                              new AssistantDetails("title", "image", "hint", null,
-                                                      "", "", "", "", "", "line 3", false, false,
-                                                      false, false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mDescriptionLine3View)).check(matches(not(isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "", "", "", "", "", "line 3",
+                        false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mDescriptionLine3View).check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -342,25 +325,20 @@
     public void testPriceAttribution() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
         /* Price attribution is set and should be visible. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "", "", "", "price attribution", false, false, false, false,
-                                        false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mPriceAttributionView))
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "", "",
+                        "price attribution", false, false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mPriceAttributionView)
                 .check(matches(allOf(withText("price attribution"), isDisplayed())));
 
         /* Price attribution is not set and should be invisible. */
-        runOnUiThreadBlocking(()
-                                      -> model.set(AssistantDetailsModel.DETAILS,
-                                              new AssistantDetails("title", "image", "hint", null,
-                                                      "", "", "", "", "", "", false, false, false,
-                                                      false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mPriceAttributionView)).check(matches(not(isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "", "", "", "", "", "", false,
+                        false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mPriceAttributionView).check(matches(not(isDisplayed())));
     }
 
     @Test
@@ -368,77 +346,66 @@
     public void testHighlighting() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
         /* Check that title is highlighted. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "line 1", "line 2", "line 3", "Est. total", true, true,
-                                        false, false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView)).check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
-        onView(is(viewHolder.mDescriptionLine1View))
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
+                        "line 2", "line 3", "Est. total", true, true, false, false, false,
+                        NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
+        onView(viewMatchers.mDescriptionLine1View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine2View))
+        onView(viewMatchers.mDescriptionLine2View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine3View))
+        onView(viewMatchers.mDescriptionLine3View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mPriceAttributionView))
+        onView(viewMatchers.mPriceAttributionView)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
 
         /* Check that description 1 is highlighted. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "line 1", "line 2", "line 3", "Est. total", true, false,
-                                        true, false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView))
-                .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine1View))
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
+                        "line 2", "line 3", "Est. total", true, false, true, false, false,
+                        NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
+        onView(viewMatchers.mDescriptionLine1View)
                 .check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
-        onView(is(viewHolder.mDescriptionLine2View))
+        onView(viewMatchers.mDescriptionLine2View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine3View))
+        onView(viewMatchers.mDescriptionLine3View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mPriceAttributionView))
+        onView(viewMatchers.mPriceAttributionView)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
 
         /* Check that description 2 is highlighted. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "line 1", "line 2", "line 3", "Est. total", true, false,
-                                        false, true, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView))
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
+                        "line 2", "line 3", "Est. total", true, false, false, true, false,
+                        NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
+        onView(viewMatchers.mDescriptionLine1View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine1View))
-                .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine2View))
+        onView(viewMatchers.mDescriptionLine2View)
                 .check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
-        onView(is(viewHolder.mDescriptionLine3View))
+        onView(viewMatchers.mDescriptionLine3View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mPriceAttributionView))
+        onView(viewMatchers.mPriceAttributionView)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
 
         /* Check that description 3 and price attribution are highlighted. */
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "image", "hint", null, "Total", "$12",
-                                        "line 1", "line 2", "line 3", "Est. total", true, false,
-                                        false, false, true, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView))
+        setDetails(model,
+                new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
+                        "line 2", "line 3", "Est. total", true, false, false, false, true,
+                        NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
+        onView(viewMatchers.mDescriptionLine1View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine1View))
+        onView(viewMatchers.mDescriptionLine2View)
                 .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine2View))
-                .check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
-        onView(is(viewHolder.mDescriptionLine3View))
+        onView(viewMatchers.mDescriptionLine3View)
                 .check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
-        onView(is(viewHolder.mPriceAttributionView))
+        onView(viewMatchers.mPriceAttributionView)
                 .check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
     }
 
@@ -446,15 +413,12 @@
     @MediumTest
     public void testStyleSpans() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
-        AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        createCoordinator(model);
 
-        runOnUiThreadBlocking(() -> {
-            model.set(AssistantDetailsModel.DETAILS,
-                    new AssistantDetails("<b>title</b>", "image", "hint", null, "<b>Total</b>",
-                            "<b>$12</b>", "<b>line 1</b>", "<b>line 2</b>", "", "<b>line 3</b>",
-                            false, false, false, false, false, NO_PLACEHOLDERS));
-        });
+        setDetails(model,
+                new AssistantDetails("<b>title</b>", "image", "hint", null, "<b>Total</b>",
+                        "<b>$12</b>", "<b>line 1</b>", "<b>line 2</b>", "", "<b>line 3</b>", false,
+                        false, false, false, false, NO_PLACEHOLDERS));
 
         onView(withText("title"))
                 .check(matches(hasTypefaceSpan(0, "title".length() - 1, Typeface.BOLD)));
@@ -475,37 +439,53 @@
     public void testPlaceholders() throws Exception {
         AssistantDetailsModel model = new AssistantDetailsModel();
         AssistantDetailsCoordinator coordinator = createCoordinator(model);
-        ViewHolder viewHolder = runOnUiThreadBlocking(() -> new ViewHolder(coordinator.getView()));
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
 
         // Without placeholders, the image and descriptions are hidden. The title is always
         // displayed.
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "", "hint", null, "", "", "", "", "",
-                                        "", false, false, false, false, false, NO_PLACEHOLDERS)));
-        onView(is(viewHolder.mTitleView)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mImageView)).check(matches(not(isDisplayed())));
-        onView(is(viewHolder.mDescriptionLine1View)).check(matches(not(isDisplayed())));
-        onView(is(viewHolder.mDescriptionLine2View)).check(matches(not(isDisplayed())));
-        onView(is(viewHolder.mDescriptionLine3View)).check(matches(not(isDisplayed())));
+        setDetails(model,
+                new AssistantDetails("title", "", "hint", null, "", "", "", "", "", "", false,
+                        false, false, false, false, NO_PLACEHOLDERS));
+        onView(viewMatchers.mTitleView).check(matches(isDisplayed()));
+        onView(viewMatchers.mImageView).check(matches(not(isDisplayed())));
+        onView(viewMatchers.mDescriptionLine1View).check(matches(not(isDisplayed())));
+        onView(viewMatchers.mDescriptionLine2View).check(matches(not(isDisplayed())));
+        onView(viewMatchers.mDescriptionLine3View).check(matches(not(isDisplayed())));
 
         // With placeholders, the image and descriptions are displayed.
-        runOnUiThreadBlocking(
-                ()
-                        -> model.set(AssistantDetailsModel.DETAILS,
-                                new AssistantDetails("title", "", "hint", null, "", "", "", "", "",
-                                        "", false, false, false, false, false,
-                                        new AssistantPlaceholdersConfiguration(
-                                                /* showImagePlaceholder= */ true,
-                                                /* showTitlePlaceholder= */ true,
-                                                /* showDescriptionLine1Placeholder= */ true,
-                                                /* showDescriptionLine2Placeholder= */ true,
-                                                /* showDescriptionLine3Placeholder= */ true))));
-        onView(is(viewHolder.mTitleView)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mImageView)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mDescriptionLine1View)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mDescriptionLine2View)).check(matches(isDisplayed()));
-        onView(is(viewHolder.mDescriptionLine3View)).check(matches(isDisplayed()));
+        setDetails(model,
+                new AssistantDetails("title", "", "hint", null, "", "", "", "", "", "", false,
+                        false, false, false, false,
+                        new AssistantPlaceholdersConfiguration(
+                                /* showImagePlaceholder= */ true,
+                                /* showTitlePlaceholder= */ true,
+                                /* showDescriptionLine1Placeholder= */ true,
+                                /* showDescriptionLine2Placeholder= */ true,
+                                /* showDescriptionLine3Placeholder= */ true)));
+        onView(viewMatchers.mTitleView).check(matches(isDisplayed()));
+        onView(viewMatchers.mImageView).check(matches(isDisplayed()));
+        onView(viewMatchers.mDescriptionLine1View).check(matches(isDisplayed()));
+        onView(viewMatchers.mDescriptionLine2View).check(matches(isDisplayed()));
+        onView(viewMatchers.mDescriptionLine3View).check(matches(isDisplayed()));
+    }
+
+    @Test
+    @MediumTest
+    public void testMultipleDetails() throws Exception {
+        AssistantDetailsModel model = new AssistantDetailsModel();
+        AssistantDetailsCoordinator coordinator = createCoordinator(model);
+        ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
+
+        setDetails(model,
+                new AssistantDetails("title 1", "", "", null, "", "", "", "", "", "", false, false,
+                        false, false, false, NO_PLACEHOLDERS),
+                new AssistantDetails("title 2", "", "", null, "", "", "", "", "", "", false, false,
+                        false, false, false, NO_PLACEHOLDERS),
+                new AssistantDetails("title 3", "", "", null, "", "", "", "", "", "", false, false,
+                        false, false, false, NO_PLACEHOLDERS));
+
+        onView(allOf(viewMatchers.mTitleView, withText("title 1"))).check(matches(isDisplayed()));
+        onView(allOf(viewMatchers.mTitleView, withText("title 2"))).check(matches(isDisplayed()));
+        onView(allOf(viewMatchers.mTitleView, withText("title 3"))).check(matches(isDisplayed()));
     }
 }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
index 0f54bcd..a05c223 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
@@ -46,7 +46,6 @@
 import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantCarouselModel;
 import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip;
 import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetails;
-import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsModel;
 import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel;
 import org.chromium.chrome.browser.autofill_assistant.infobox.AssistantInfoBox;
 import org.chromium.chrome.browser.autofill_assistant.infobox.AssistantInfoBoxModel;
@@ -180,9 +179,8 @@
         String descriptionLine3 = "This is a fancy line3";
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> assistantCoordinator.getModel().getDetailsModel().set(
-                                AssistantDetailsModel.DETAILS,
-                                new AssistantDetails(movieTitle,
+                        -> assistantCoordinator.getModel().getDetailsModel().setDetailsList(
+                                Arrays.asList(new AssistantDetails(movieTitle,
                                         /* imageUrl = */ "",
                                         /* imageAccessibilityHint = */ "",
                                         /* imageClickthroughData = */ null,
@@ -194,7 +192,7 @@
                                         /* highlightTitle= */ false, /* highlightLine1= */
                                         false, /* highlightLine2 = */ false,
                                         /* highlightLine3 = */ false,
-                                        AutofillAssistantDetailsUiTest.NO_PLACEHOLDERS)));
+                                        AutofillAssistantDetailsUiTest.NO_PLACEHOLDERS))));
         onView(withId(R.id.details_title))
                 .check(matches(allOf(withText(movieTitle), withEffectiveVisibility(VISIBLE))));
         onView(withId(R.id.details_line1))
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 0b14a0c..081be31 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -37,6 +37,7 @@
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BundleUtils;
 import org.chromium.base.Callback;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
@@ -1398,7 +1399,12 @@
             VrModuleProvider.getDelegate().onNewIntentWithNative(this, getIntent());
         }
 
+        // The first launch of the screenshot feature benefits from this DFM being installed
+        // proactively. However without the isolated split feature there are performance regressions
+        // as a result of adding this extra code.
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_SHARE_SCREENSHOT)
+                && BundleUtils.isolatedSplitsEnabled()
+                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
                 && AppHooks.get().getImageEditorModuleProvider() != null) {
             AppHooks.get().getImageEditorModuleProvider().maybeInstallModuleDeferred();
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java b/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
index 94cc229..6c768e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/DexFixer.java
@@ -18,6 +18,7 @@
 import org.chromium.base.BuildConfig;
 import org.chromium.base.BuildInfo;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.JavaExceptionReporter;
 import org.chromium.base.Log;
 import org.chromium.base.compat.ApiHelperForM;
 import org.chromium.base.compat.ApiHelperForO;
@@ -29,6 +30,7 @@
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.version.ChromeVersionInfo;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.io.File;
 import java.io.IOException;
@@ -41,6 +43,12 @@
     private static final String TAG = "DexFixer";
     private static boolean sHasIsolatedSplits;
 
+    private static class DexFixerException extends Exception {
+        DexFixerException(String reason, Throwable causedBy) {
+            super(reason, causedBy);
+        }
+    }
+
     @WorkerThread
     public static void fixDexInBackground() {
         if (shouldSkipDexFix()) {
@@ -77,16 +85,23 @@
         int reason = needsDexCompile(appInfo);
         if (reason > DexFixerReason.NOT_NEEDED) {
             Log.w(TAG, "Triggering dex compile. Reason=%d", reason);
+            String cmd = "cmd package compile -r shared ";
+            if (reason == DexFixerReason.NOT_READABLE && BuildConfig.ISOLATED_SPLITS_ENABLED) {
+                // Isolated processes need only access the base split.
+                String apkBaseName = new File(appInfo.sourceDir).getName();
+                cmd += String.format("--split %s ", apkBaseName);
+            }
+            cmd += ContextUtils.getApplicationContext().getPackageName();
             try {
-                String cmd = "cmd package compile -r shared ";
-                if (reason == DexFixerReason.NOT_READABLE && BuildConfig.ISOLATED_SPLITS_ENABLED) {
-                    // Isolated processes need only access the base split.
-                    String apkBaseName = new File(appInfo.sourceDir).getName();
-                    cmd += String.format("--split %s ", apkBaseName);
-                }
-                cmd += ContextUtils.getApplicationContext().getPackageName();
                 runtime.exec(cmd);
             } catch (IOException e) {
+                DexFixerException dfException =
+                        new DexFixerException(String.format("Reason: %s Name: %s", reason,
+                                                      new File(appInfo.sourceDir).getName()),
+                                e);
+                // TODO(agrieve): Remove reportException() once some data is collected.
+                PostTask.postTask(UiThreadTaskTraits.BEST_EFFORT,
+                        () -> JavaExceptionReporter.reportException(dfException));
                 reason = DexFixerReason.FAILED_TO_RUN;
             }
         }
@@ -174,6 +189,11 @@
                 return DexFixerReason.NOT_READABLE;
             }
         } catch (ErrnoException e) {
+            // TODO(agrieve): Remove reportException() once some data is collected.
+            DexFixerException dfException = new DexFixerException(
+                    String.format("Path: %s exists: %s", oatPath, new File(oatPath).exists()), e);
+            PostTask.postTask(UiThreadTaskTraits.BEST_EFFORT,
+                    () -> JavaExceptionReporter.reportException(dfException));
             return DexFixerReason.STAT_FAILED;
         }
         return DexFixerReason.NOT_NEEDED;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java b/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java
index 4a192210..ac452ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java
@@ -8,6 +8,7 @@
 import android.app.Activity;
 
 import androidx.annotation.MainThread;
+import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
@@ -68,28 +69,28 @@
         });
     }
 
+    @VisibleForTesting
     @CalledByNative
-    private static void reauthenticateChildAccount(
-            WindowAndroid windowAndroid, String accountName, final long nativeCallback) {
+    static void reauthenticateChildAccount(
+            WindowAndroid windowAndroid, String accountName, final long nativeOnFailureCallback) {
         ThreadUtils.assertOnUiThread();
-
-        Activity activity = windowAndroid.getActivity().get();
+        final Activity activity = windowAndroid.getActivity().get();
         if (activity == null) {
-            PostTask.postTask(UiThreadTaskTraits.DEFAULT,
-                    ()
-                            -> ChildAccountServiceJni.get().onReauthenticationResult(
-                                    nativeCallback, false));
+            PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
+                ChildAccountServiceJni.get().onReauthenticationFailed(nativeOnFailureCallback);
+            });
             return;
         }
-
         Account account = AccountUtils.createAccountFromName(accountName);
-        AccountManagerFacadeProvider.getInstance().updateCredentials(account, activity,
-                result
-                -> ChildAccountServiceJni.get().onReauthenticationResult(nativeCallback, result));
+        AccountManagerFacadeProvider.getInstance().updateCredentials(account, activity, success -> {
+            if (!success) {
+                ChildAccountServiceJni.get().onReauthenticationFailed(nativeOnFailureCallback);
+            }
+        });
     }
 
     @NativeMethods
     interface Natives {
-        void onReauthenticationResult(long callbackPtr, boolean reauthSuccessful);
+        void onReauthenticationFailed(long onFailureCallbackPtr);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java
index eb33839..f9d9b01b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java
@@ -13,7 +13,6 @@
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.SigninManager;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
-import org.chromium.chrome.browser.sync.settings.AccountManagementFragment;
 import org.chromium.components.externalauth.ExternalAuthUtils;
 import org.chromium.components.externalauth.UserRecoverableErrorHandler;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
@@ -47,9 +46,7 @@
      */
     public static void start() {
         ChildAccountService.checkChildAccountStatus(status -> {
-            boolean hasChildAccount = ChildAccountStatus.isChild(status);
-            AccountManagementFragment.setSignOutAllowedPreferenceValue(!hasChildAccount);
-            if (hasChildAccount) {
+            if (ChildAccountStatus.isChild(status)) {
                 // Account cache is already available when child account status is ready.
                 final List<Account> accounts =
                         AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts();
@@ -65,8 +62,7 @@
      */
     private static void signinAndEnableSync(final Account childAccount) {
         final Profile profile = Profile.getLastUsedRegularProfile();
-        if (FirstRunUtils.canAllowSync()
-                && IdentityServicesProvider.get().getIdentityManager(profile).hasPrimaryAccount()) {
+        if (IdentityServicesProvider.get().getIdentityManager(profile).hasPrimaryAccount()) {
             // TODO(https://crbug.com/1044206): Remove this.
             ProfileSyncService.get().setFirstSetupComplete(SyncFirstSetupCompleteSource.BASIC_FLOW);
         }
@@ -74,7 +70,7 @@
                 IdentityServicesProvider.get().getSigninManager(profile);
         // By definition we have finished all the checks for first run.
         signinManager.onFirstRunCheckDone();
-        if (FirstRunUtils.canAllowSync() && signinManager.isSignInAllowed()) {
+        if (signinManager.isSignInAllowed()) {
             signinManager.signinAndEnableSync(SigninAccessPoint.FORCED_SIGNIN, childAccount,
                     new SigninManager.SignInCallback() {
                         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinatorPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinatorPhone.java
index d365379..26577972 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinatorPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinatorPhone.java
@@ -5,10 +5,12 @@
 package org.chromium.chrome.browser.omnibox;
 
 import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.view.View;
 import android.widget.FrameLayout;
 
 import org.chromium.chrome.browser.omnibox.status.StatusCoordinator;
+import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
 import java.util.List;
 
@@ -32,11 +34,19 @@
     }
 
     /**
-     * Returns width of child views before the first view that would be visible when location
-     * bar is focused. The first visible, focused view should be either url bar or status icon.
+     * Returns the total width of child views before the first view that would be visible when
+     * location bar is focused. The first visible, focused view should be either url bar or status
+     * icon.
      */
     public int getOffsetOfFirstVisibleFocusedView() {
-        return mLocationBarPhone.getOffsetOfFirstVisibleFocusedView();
+        int visibleWidth = 0;
+        for (int i = 0; i < mLocationBarPhone.getChildCount(); i++) {
+            View child = mLocationBarPhone.getChildAt(i);
+            if (child == mLocationBarPhone.getFirstVisibleFocusedView()) break;
+            if (child.getVisibility() == View.GONE) continue;
+            visibleWidth += child.getMeasuredWidth();
+        }
+        return visibleWidth;
     }
 
     /**
@@ -49,7 +59,15 @@
      */
     public void populateFadeAnimations(
             List<Animator> animators, long startDelayMs, long durationMs, float targetAlpha) {
-        mLocationBarPhone.populateFadeAnimations(animators, startDelayMs, durationMs, targetAlpha);
+        for (int i = 0; i < mLocationBarPhone.getChildCount(); i++) {
+            View child = mLocationBarPhone.getChildAt(i);
+            if (child == mLocationBarPhone.getFirstVisibleFocusedView()) break;
+            Animator animator = ObjectAnimator.ofFloat(child, View.ALPHA, targetAlpha);
+            animator.setStartDelay(startDelayMs);
+            animator.setDuration(durationMs);
+            animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+            animators.add(animator);
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
index 3cf14d7..4c76425 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.omnibox;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -13,12 +11,8 @@
 import android.view.TouchDelegate;
 import android.view.View;
 import android.widget.FrameLayout;
-
 import org.chromium.base.TraceEvent;
 import org.chromium.chrome.R;
-import org.chromium.ui.interpolators.BakedBezierInterpolator;
-
-import java.util.List;
 
 /**
  * A location bar implementation specific for smaller/phone screens.
@@ -206,38 +200,11 @@
     }
 
     /**
-     * @return Width of child views before the first view that would be visible when location bar is
-     *         focused. The first visible, focused view should be either url bar or status icon.
+     * Returns the first child view that would be visible when location bar is focused. The first
+     * visible, focused view should be either url bar or status icon.
      */
-    public int getOffsetOfFirstVisibleFocusedView() {
-        int visibleWidth = 0;
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child == mFirstVisibleFocusedView) break;
-            if (child.getVisibility() == GONE) continue;
-            visibleWidth += child.getMeasuredWidth();
-        }
-        return visibleWidth;
-    }
-
-    /**
-     * Populates fade animators of status icon for location bar focus change animation.
-     * @param animators The target list to add animators to.
-     * @param startDelayMs Start delay of fade animation in milliseconds.
-     * @param durationMs Duration of fade animation in milliseconds.
-     * @param targetAlpha Target alpha value.
-     */
-    public void populateFadeAnimations(
-            List<Animator> animators, long startDelayMs, long durationMs, float targetAlpha) {
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child == mFirstVisibleFocusedView) break;
-            Animator animator = ObjectAnimator.ofFloat(child, ALPHA, targetAlpha);
-            animator.setStartDelay(startDelayMs);
-            animator.setDuration(durationMs);
-            animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
-            animators.add(animator);
-        }
+    /* package */ View getFirstVisibleFocusedView() {
+        return mFirstVisibleFocusedView;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
index 0a6a2c72..b54f93e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
@@ -24,9 +24,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.Pref;
-import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileAccountManagementMetrics;
 import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate;
@@ -205,11 +203,10 @@
                 signOutPreference.setIcon(R.drawable.ic_signout_40dp);
             }
             signOutPreference.setTitle(getSignOutPreferenceText());
-            signOutPreference.setEnabled(getSignOutAllowedPreferenceValue());
             signOutPreference.setOnPreferenceClickListener(preference -> {
                 if (!isVisible() || !isResumed()) return false;
 
-                if (mSignedInAccountName != null && getSignOutAllowedPreferenceValue()) {
+                if (mSignedInAccountName != null) {
                     SigninMetricsUtils.logProfileAccountManagementMenu(
                             ProfileAccountManagementMetrics.TOGGLE_SIGNOUT, mGaiaServiceType);
 
@@ -462,22 +459,4 @@
         settingsLauncher.launchSettingsActivity(
                 ContextUtils.getApplicationContext(), AccountManagementFragment.class, arguments);
     }
-
-    /**
-     * @return Whether the sign out is not disabled due to a child/EDU account.
-     */
-    private static boolean getSignOutAllowedPreferenceValue() {
-        return SharedPreferencesManager.getInstance().readBoolean(
-                ChromePreferenceKeys.SETTINGS_SYNC_SIGN_OUT_ALLOWED, true);
-    }
-
-    /**
-     * Sets the sign out allowed preference value.
-     *
-     * @param isAllowed True if the sign out is not disabled due to a child/EDU account
-     */
-    public static void setSignOutAllowedPreferenceValue(boolean isAllowed) {
-        SharedPreferencesManager.getInstance().writeBoolean(
-                ChromePreferenceKeys.SETTINGS_SYNC_SIGN_OUT_ALLOWED, isAllowed);
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/datareduction/DataReductionPromoUtilsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/datareduction/DataReductionPromoUtilsTest.java
index bacff79..6d67c15 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/datareduction/DataReductionPromoUtilsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/datareduction/DataReductionPromoUtilsTest.java
@@ -32,7 +32,7 @@
  * Unit test suite for DataReductionPromoUtils.
  */
 @RunWith(BaseJUnit4ClassRunner.class)
-@Batch(Batch.UNIT_TESTS)
+@Batch(Batch.PER_CLASS)
 public class DataReductionPromoUtilsTest {
     @Rule
     public final ChromeBrowserTestRule mChromeBrowserTestRule = new ChromeBrowserTestRule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/datareduction/settings/DataReductionStatsPreferenceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/datareduction/settings/DataReductionStatsPreferenceTest.java
index d1dc6b0..064e155 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/datareduction/settings/DataReductionStatsPreferenceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/datareduction/settings/DataReductionStatsPreferenceTest.java
@@ -34,7 +34,7 @@
  * Unit test suite for DataReductionStatsPreference.
  */
 @RunWith(BaseJUnit4ClassRunner.class)
-@Batch(Batch.UNIT_TESTS)
+@Batch(Batch.PER_CLASS)
 public class DataReductionStatsPreferenceTest {
     @Rule
     public final ChromeBrowserTestRule mChromeBrowserTestRule = new ChromeBrowserTestRule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceRenderTest.java
index 49f1988cde..1383eda6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceRenderTest.java
@@ -27,6 +27,7 @@
 import org.mockito.junit.MockitoRule;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -80,6 +81,7 @@
 
     @Test
     @MediumTest
+    @DisabledTest(message = "crbug.com/1165682")
     @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:colorful_mic/true"})
     @Feature({"RenderTest"})
     public void testAssistantColorfulMic() throws IOException {
@@ -107,4 +109,4 @@
         mRenderTestRule.render(
                 mActivityTestRule.getActivity().findViewById(R.id.toolbar), "avs_mic_focused");
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/childaccounts/ChildAccountServiceTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/childaccounts/ChildAccountServiceTest.java
index 18240c5..cbd0facc 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/childaccounts/ChildAccountServiceTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/childaccounts/ChildAccountServiceTest.java
@@ -4,10 +4,21 @@
 
 package org.chromium.chrome.browser.childaccounts;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.accounts.Account;
+import android.app.Activity;
 
+import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -15,12 +26,17 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import org.chromium.base.Callback;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.components.signin.AccountManagerFacade.ChildAccountStatusListener;
 import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.ChildAccountStatus;
 import org.chromium.components.signin.test.util.FakeAccountManagerFacade;
+import org.chromium.ui.base.WindowAndroid;
+
+import java.lang.ref.WeakReference;
 
 /**
  * Unit tests for {@link ChildAccountService}.
@@ -29,26 +45,41 @@
 public class ChildAccountServiceTest {
     private static final Account CHILD_ACCOUNT =
             AccountUtils.createAccountFromName("child.account@gmail.com");
+    private static final long FAKE_NATIVE_CALLBACK = 1000L;
 
-    private final FakeAccountManagerFacade mFakeFacade = new FakeAccountManagerFacade(null) {
+    private final FakeAccountManagerFacade mFakeFacade = spy(new FakeAccountManagerFacade(null) {
         @Override
         public void checkChildAccountStatus(Account account, ChildAccountStatusListener listener) {
             listener.onStatusReady(account.name.startsWith("child")
                             ? ChildAccountStatus.REGULAR_CHILD
                             : ChildAccountStatus.NOT_CHILD);
         }
-    };
+    });
 
     @Rule
     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     @Rule
+    public final JniMocker mocker = new JniMocker();
+
+    @Rule
     public final AccountManagerTestRule mAccountManagerTestRule =
             new AccountManagerTestRule(mFakeFacade);
 
     @Mock
     private ChildAccountStatusListener mListenerMock;
 
+    @Mock
+    private ChildAccountService.Natives mNativeMock;
+
+    @Mock
+    private WindowAndroid mWindowAndroidMock;
+
+    @Before
+    public void setUp() {
+        mocker.mock(ChildAccountServiceJni.TEST_HOOKS, mNativeMock);
+    }
+
     @Test
     public void testChildAccountStatusWhenNoAccountsOnDevice() {
         ChildAccountService.checkChildAccountStatus(mListenerMock);
@@ -95,4 +126,50 @@
         ChildAccountService.checkChildAccountStatus(mListenerMock);
         verify(mListenerMock).onStatusReady(ChildAccountStatus.REGULAR_CHILD);
     }
+
+    @Test
+    public void testReauthenticateChildAccountWhenActivityIsNull() {
+        when(mWindowAndroidMock.getActivity()).thenReturn(new WeakReference<>(null));
+        ChildAccountService.reauthenticateChildAccount(
+                mWindowAndroidMock, CHILD_ACCOUNT.name, FAKE_NATIVE_CALLBACK);
+        verify(mNativeMock).onReauthenticationFailed(FAKE_NATIVE_CALLBACK);
+    }
+
+    @Test
+    public void testReauthenticateChildAccountWhenReauthenticationSucceeded() {
+        final Activity activity = mock(Activity.class);
+        when(mWindowAndroidMock.getActivity()).thenReturn(new WeakReference<>(activity));
+        doAnswer(invocation -> {
+            Account account = invocation.getArgument(0);
+            Assert.assertEquals(CHILD_ACCOUNT.name, account.name);
+            Callback<Boolean> callback = invocation.getArgument(2);
+            callback.onResult(true);
+            return null;
+        })
+                .when(mFakeFacade)
+                .updateCredentials(any(Account.class), eq(activity), any());
+
+        ChildAccountService.reauthenticateChildAccount(
+                mWindowAndroidMock, CHILD_ACCOUNT.name, FAKE_NATIVE_CALLBACK);
+        verify(mNativeMock, never()).onReauthenticationFailed(anyLong());
+    }
+
+    @Test
+    public void testReauthenticateChildAccountWhenReauthenticationFailed() {
+        final Activity activity = mock(Activity.class);
+        when(mWindowAndroidMock.getActivity()).thenReturn(new WeakReference<>(activity));
+        doAnswer(invocation -> {
+            Account account = invocation.getArgument(0);
+            Assert.assertEquals(CHILD_ACCOUNT.name, account.name);
+            Callback<Boolean> callback = invocation.getArgument(2);
+            callback.onResult(false);
+            return null;
+        })
+                .when(mFakeFacade)
+                .updateCredentials(any(Account.class), eq(activity), any());
+
+        ChildAccountService.reauthenticateChildAccount(
+                mWindowAndroidMock, CHILD_ACCOUNT.name, FAKE_NATIVE_CALLBACK);
+        verify(mNativeMock).onReauthenticationFailed(FAKE_NATIVE_CALLBACK);
+    }
 }
\ No newline at end of file
diff --git a/chrome/android/modules/buildflags.gni b/chrome/android/modules/buildflags.gni
index b578193..fc75cbfe 100644
--- a/chrome/android/modules/buildflags.gni
+++ b/chrome/android/modules/buildflags.gni
@@ -11,10 +11,7 @@
   # Whether //chrome code and resources are in a DFM for Monochrome and
   # Trichrome bundles. This module will also include code and resources from all
   # other DFMs.
-  # TODO(crbug.com/1126301): The binary size tools need to be updated to include
-  # DFM code before this can be enabled on stable.
-  enable_chrome_module = android_channel == "default" ||
-                         android_channel == "canary" || android_channel == "dev"
+  enable_chrome_module = true
 
   # Whether to enable DFMs which depend on the chrome DFM. These will be split
   # out of the chrome DFM using DexSplitter.
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 5ea8be8..24ce282 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-89.0.4385.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-89.0.4386.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index b26d6013..70c7ad6 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1120,6 +1120,9 @@
   <message name="IDS_LOGIN_MARKETING_OPT_IN_SCREEN_SUBTITLE" desc="The sub-title of the dialog that allows user to opt-in into several Google marketing options.">
     Get <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> tips, offers, and updates, and share feedback. Unsubscribe anytime.
   </message>
+  <message name="IDS_LOGIN_MARKETING_OPT_IN_SCREEN_FOOTER_NOTICE" desc="A notice to the user shown in the footer of the marketing opt-in screen.">
+    Unsubscribe anytime by clicking the link in the emails you receive.
+  </message>
   <message name="IDS_LOGIN_MARKETING_OPT_IN_SCREEN_SUBTITLE_WITH_DEVICE_NAME" desc="The sub-title of the marketing opt in screen which will also include the name of the user's device.">
     You are ready to start using your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>.
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_MARKETING_OPT_IN_SCREEN_FOOTER_NOTICE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_MARKETING_OPT_IN_SCREEN_FOOTER_NOTICE.png.sha1
new file mode 100644
index 0000000..b54ac12
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_MARKETING_OPT_IN_SCREEN_FOOTER_NOTICE.png.sha1
@@ -0,0 +1 @@
+491818cbeac38c8eb2de1058b20fcd128ab17c2d
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 583b8b1..36106305 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -976,8 +976,6 @@
     "optimization_guide/optimization_guide_keyed_service_factory.h",
     "optimization_guide/optimization_guide_navigation_data.cc",
     "optimization_guide/optimization_guide_navigation_data.h",
-    "optimization_guide/optimization_guide_permissions_util.cc",
-    "optimization_guide/optimization_guide_permissions_util.h",
     "optimization_guide/optimization_guide_top_host_provider.cc",
     "optimization_guide/optimization_guide_top_host_provider.h",
     "optimization_guide/optimization_guide_web_contents_observer.cc",
@@ -2273,7 +2271,7 @@
     "//components/visitedlink/common",
     "//components/web_cache/browser",
     "//components/web_resource",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//components/webdata/common",
     "//components/webdata_services",
     "//components/webrtc",
@@ -3137,6 +3135,8 @@
       "password_manager/android/password_manager_launcher_android.cc",
       "password_manager/android/password_manager_launcher_android.h",
       "password_manager/android/password_scripts_fetcher_android.cc",
+      "password_manager/android/password_store_bridge.cc",
+      "password_manager/android/password_store_bridge.h",
       "password_manager/android/save_password_infobar_delegate_android.cc",
       "password_manager/android/save_password_infobar_delegate_android.h",
       "password_manager/android/save_password_message_delegate.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 5135045..0144889 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -324,7 +324,7 @@
   "+components/web_cache/browser",
   "+components/web_modal",
   "+components/web_resource",
-  "+components/webapps",
+  "+components/webapps/browser",
   "+components/webdata/common",
   "+components/webdata_services",
   "+components/webrtc_logging/browser",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 19699f1..b37fd092 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -103,6 +103,7 @@
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/common/omnibox_features.h"
+#include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/page_info/features.h"
 #include "components/paint_preview/buildflags/buildflags.h"
 #include "components/paint_preview/features/features.h"
@@ -198,6 +199,7 @@
 #include "chrome/browser/continuous_search/features.h"
 #include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/notifications/chime/android/features.h"
+#include "chrome/browser/webapps/android/features.h"
 #include "components/browser_ui/site_settings/android/features.h"
 #include "components/external_intents/android/external_intents_feature_list.h"
 #else  // OS_ANDROID
@@ -6308,7 +6310,7 @@
      flag_descriptions::
          kContextMenuPerformanceInfoAndRemoteHintFetchingDescription,
      kOsAndroid,
-     FEATURE_VALUE_TYPE(performance_hints::features::
+     FEATURE_VALUE_TYPE(optimization_guide::features::
                             kContextMenuPerformanceInfoAndRemoteHintFetching)},
 #endif  // !defined(OS_ANDROID)
 
@@ -7026,6 +7028,13 @@
      flag_descriptions::kSendTabToSelfWhenSignedInDescription, kOsAll,
      FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfWhenSignedIn)},
 
+#if defined(OS_ANDROID)
+    {"mobile-pwa-install-use-bottom-sheet",
+     flag_descriptions::kMobilePwaInstallUseBottomSheetName,
+     flag_descriptions::kMobilePwaInstallUseBottomSheetDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(webapps::features::kPwaInstallUseBottomSheet)},
+#endif
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 0e33bbe5..428dc03b 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -1766,54 +1766,59 @@
   return Java_AssistantModel_getDetailsModel(AttachCurrentThread(), GetModel());
 }
 
-void UiControllerAndroid::OnDetailsChanged(const Details* details) {
+void UiControllerAndroid::OnDetailsChanged(
+    const std::vector<Details>& details_list) {
   JNIEnv* env = AttachCurrentThread();
+
+  auto jdetails_list = Java_AssistantDetailsModel_createDetailsList(env);
+  for (const auto& details : details_list) {
+    auto opt_image_accessibility_hint = details.imageAccessibilityHint();
+    base::android::ScopedJavaLocalRef<jstring> jimage_accessibility_hint =
+        nullptr;
+    if (opt_image_accessibility_hint.has_value()) {
+      jimage_accessibility_hint =
+          ConvertUTF8ToJavaString(env, opt_image_accessibility_hint.value());
+    }
+
+    // Create the placeholders configuration. We check here that the associated
+    // texts/urls are empty, so that on the Java side we can just check the
+    // placeholders configuration to know whether a placeholder should be shown
+    // or not.
+    auto placeholders = details.placeholders();
+    auto jplaceholders = Java_AssistantPlaceholdersConfiguration_Constructor(
+        env,
+        placeholders.show_image_placeholder() && details.imageUrl().empty(),
+        placeholders.show_title_placeholder() && details.title().empty(),
+        placeholders.show_description_line_1_placeholder() &&
+            details.descriptionLine1().empty(),
+        placeholders.show_description_line_2_placeholder() &&
+            details.descriptionLine2().empty(),
+        placeholders.show_description_line_3_placeholder() &&
+            details.descriptionLine3().empty());
+
+    auto jdetails = Java_AssistantDetails_create(
+        env, ConvertUTF8ToJavaString(env, details.title()),
+        ConvertUTF8ToJavaString(env, details.imageUrl()),
+        jimage_accessibility_hint, details.imageAllowClickthrough(),
+        ConvertUTF8ToJavaString(env, details.imageDescription()),
+        ConvertUTF8ToJavaString(env, details.imagePositiveText()),
+        ConvertUTF8ToJavaString(env, details.imageNegativeText()),
+        ConvertUTF8ToJavaString(env, details.imageClickthroughUrl()),
+        ConvertUTF8ToJavaString(env, details.totalPriceLabel()),
+        ConvertUTF8ToJavaString(env, details.totalPrice()),
+        ConvertUTF8ToJavaString(env, details.descriptionLine1()),
+        ConvertUTF8ToJavaString(env, details.descriptionLine2()),
+        ConvertUTF8ToJavaString(env, details.descriptionLine3()),
+        ConvertUTF8ToJavaString(env, details.priceAttribution()),
+        details.userApprovalRequired(), details.highlightTitle(),
+        details.highlightLine1(), details.highlightLine2(),
+        details.highlightLine3(), jplaceholders);
+
+    Java_AssistantDetailsModel_addDetails(env, jdetails_list, jdetails);
+  }
+
   auto jmodel = GetDetailsModel();
-  if (!details) {
-    Java_AssistantDetailsModel_clearDetails(env, jmodel);
-    return;
-  }
-  auto opt_image_accessibility_hint = details->imageAccessibilityHint();
-  base::android::ScopedJavaLocalRef<jstring> jimage_accessibility_hint =
-      nullptr;
-  if (opt_image_accessibility_hint.has_value()) {
-    jimage_accessibility_hint =
-        ConvertUTF8ToJavaString(env, opt_image_accessibility_hint.value());
-  }
-
-  // Create the placeholders configuration. We check here that the associated
-  // texts/urls are empty, so that on the Java side we can just check the
-  // placeholders configuration to know whether a placeholder should be shown or
-  // not.
-  auto placeholders = details->placeholders();
-  auto jplaceholders = Java_AssistantPlaceholdersConfiguration_Constructor(
-      env, placeholders.show_image_placeholder() && details->imageUrl().empty(),
-      placeholders.show_title_placeholder() && details->title().empty(),
-      placeholders.show_description_line_1_placeholder() &&
-          details->descriptionLine1().empty(),
-      placeholders.show_description_line_2_placeholder() &&
-          details->descriptionLine2().empty(),
-      placeholders.show_description_line_3_placeholder() &&
-          details->descriptionLine3().empty());
-
-  auto jdetails = Java_AssistantDetails_create(
-      env, ConvertUTF8ToJavaString(env, details->title()),
-      ConvertUTF8ToJavaString(env, details->imageUrl()),
-      jimage_accessibility_hint, details->imageAllowClickthrough(),
-      ConvertUTF8ToJavaString(env, details->imageDescription()),
-      ConvertUTF8ToJavaString(env, details->imagePositiveText()),
-      ConvertUTF8ToJavaString(env, details->imageNegativeText()),
-      ConvertUTF8ToJavaString(env, details->imageClickthroughUrl()),
-      ConvertUTF8ToJavaString(env, details->totalPriceLabel()),
-      ConvertUTF8ToJavaString(env, details->totalPrice()),
-      ConvertUTF8ToJavaString(env, details->descriptionLine1()),
-      ConvertUTF8ToJavaString(env, details->descriptionLine2()),
-      ConvertUTF8ToJavaString(env, details->descriptionLine3()),
-      ConvertUTF8ToJavaString(env, details->priceAttribution()),
-      details->userApprovalRequired(), details->highlightTitle(),
-      details->highlightLine1(), details->highlightLine2(),
-      details->highlightLine3(), jplaceholders);
-  Java_AssistantDetailsModel_setDetails(env, jmodel, jdetails);
+  Java_AssistantDetailsModel_setDetailsList(env, jmodel, jdetails_list);
 }
 
 // InfoBox related method.
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index 9f03a66..c721195 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -97,7 +97,7 @@
       const CollectUserDataOptions* collect_user_data_options) override;
   void OnUserDataChanged(const UserData* state,
                          UserData::FieldChange field_change) override;
-  void OnDetailsChanged(const Details* details) override;
+  void OnDetailsChanged(const std::vector<Details>& details) override;
   void OnInfoBoxChanged(const InfoBox* info_box) override;
   void OnProgressChanged(int progress) override;
   void OnProgressActiveStepChanged(int active_step) override;
diff --git a/chrome/browser/android/instantapps/instant_apps_settings.cc b/chrome/browser/android/instantapps/instant_apps_settings.cc
index de56bd8..50a942f 100644
--- a/chrome/browser/android/instantapps/instant_apps_settings.cc
+++ b/chrome/browser/android/instantapps/instant_apps_settings.cc
@@ -11,7 +11,7 @@
 #include "base/values.h"
 #include "chrome/android/chrome_jni_headers/InstantAppsSettings_jni.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
-#include "components/webapps/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_logging.h"
 #include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/android/metrics/launch_metrics.cc b/chrome/browser/android/metrics/launch_metrics.cc
index 759b28843..53f1f480 100644
--- a/chrome/browser/android/metrics/launch_metrics.cc
+++ b/chrome/browser/android/metrics/launch_metrics.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/prefs/pref_metrics_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/site_engagement/content/site_engagement_service.h"
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index 27b39a6..b1101692 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -14,7 +14,7 @@
 #include "base/guid.h"
 #include "base/strings/string16.h"
 #include "chrome/android/chrome_jni_headers/ShortcutHelper_jni.h"
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 #include "content/public/browser/manifest_icon_downloader.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/android/color_helpers.h"
diff --git a/chrome/browser/android/webapk/webapk_install_service.cc b/chrome/browser/android/webapk/webapk_install_service.cc
index d51005e..db580e4 100644
--- a/chrome/browser/android/webapk/webapk_install_service.cc
+++ b/chrome/browser/android/webapk/webapk_install_service.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/android/shortcut_helper.h"
 #include "chrome/browser/android/webapk/webapk_install_service_factory.h"
 #include "chrome/browser/android/webapk/webapk_installer.h"
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 #include "ui/gfx/android/java_bitmap.h"
 
 // static
diff --git a/chrome/browser/android/webapk/webapk_install_service.h b/chrome/browser/android/webapk/webapk_install_service.h
index 4788821..bd49bdaa 100644
--- a/chrome/browser/android/webapk/webapk_install_service.h
+++ b/chrome/browser/android/webapk/webapk_install_service.h
@@ -16,7 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index ea9b8bea..f9867bb 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -38,7 +38,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/version_info/version_info.h"
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/browsing_data_remover.h"
diff --git a/chrome/browser/android/webapk/webapk_installer_unittest.cc b/chrome/browser/android/webapk/webapk_installer_unittest.cc
index f914eed4..b5f7c97 100644
--- a/chrome/browser/android/webapk/webapk_installer_unittest.cc
+++ b/chrome/browser/android/webapk/webapk_installer_unittest.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/android/webapk/webapk_install_service.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
index ced563d..61411f0 100644
--- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
+++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -18,9 +18,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/android/chrome_jni_headers/WebApkUpdateDataFetcher_jni.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/webapps/android/webapps_icon_utils.h"
-#include "components/webapps/android/webapps_utils.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/android/webapps_icon_utils.h"
+#include "components/webapps/browser/android/webapps_utils.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.h b/chrome/browser/android/webapk/webapk_update_data_fetcher.h
index 29d5e7e..e7479ad 100644
--- a/chrome/browser/android/webapk/webapk_update_data_fetcher.h
+++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.h
@@ -11,7 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "chrome/browser/android/webapk/webapk_icon_hasher.h"
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
diff --git a/chrome/browser/android/webapk/webapk_update_manager.cc b/chrome/browser/android/webapk/webapk_update_manager.cc
index 5bf2a66a4..42f9571 100644
--- a/chrome/browser/android/webapk/webapk_update_manager.cc
+++ b/chrome/browser/android/webapk/webapk_update_manager.cc
@@ -22,7 +22,7 @@
 #include "chrome/browser/android/webapk/webapk_installer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/android/webapps/add_to_homescreen_coordinator.cc b/chrome/browser/android/webapps/add_to_homescreen_coordinator.cc
index cf2ab31f..e4bbffc 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_coordinator.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_coordinator.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/android/webapps/add_to_homescreen_installer.h"
 #include "chrome/browser/android/webapps/add_to_homescreen_mediator.h"
 #include "chrome/browser/banners/app_banner_manager.h"
-#include "components/webapps/android/add_to_homescreen_params.h"
+#include "components/webapps/browser/android/add_to_homescreen_params.h"
 
 namespace webapps {
 
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
index e8619b6..ffb389f 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -19,16 +19,14 @@
 #include "base/task/thread_pool.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/android/shortcut_helper.h"
-#include "chrome/browser/favicon/favicon_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
 #include "components/dom_distiller/core/url_utils.h"
-#include "components/favicon/core/favicon_service.h"
+#include "components/favicon/content/large_favicon_provider_getter.h"
+#include "components/favicon/core/large_favicon_provider.h"
 #include "components/favicon_base/favicon_types.h"
-#include "components/webapps/android/webapps_icon_utils.h"
-#include "components/webapps/android/webapps_utils.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/android/webapps_icon_utils.h"
+#include "components/webapps/browser/android/webapps_utils.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -313,20 +311,16 @@
       {favicon_base::IconType::kTouchPrecomposedIcon,
        favicon_base::IconType::kTouchIcon}};
 
-  favicon::FaviconService* favicon_service =
-      FaviconServiceFactory::GetForProfile(
-          Profile::FromBrowserContext(web_contents()->GetBrowserContext()),
-          ServiceAccessType::EXPLICIT_ACCESS);
-
   // Using favicon if its size is not smaller than platform required size,
   // otherwise using the largest icon among all available icons.
   int threshold_to_get_any_largest_icon =
       WebappsIconUtils::GetIdealHomescreenIconSizeInPx() - 1;
-  favicon_service->GetLargestRawFaviconForPageURL(
-      shortcut_info_.url, icon_types, threshold_to_get_any_largest_icon,
-      base::BindOnce(&AddToHomescreenDataFetcher::OnFaviconFetched,
-                     weak_ptr_factory_.GetWeakPtr()),
-      &favicon_task_tracker_);
+  favicon::GetLargeFaviconProvider(web_contents()->GetBrowserContext())
+      ->GetLargestRawFaviconForPageURL(
+          shortcut_info_.url, icon_types, threshold_to_get_any_largest_icon,
+          base::BindOnce(&AddToHomescreenDataFetcher::OnFaviconFetched,
+                         weak_ptr_factory_.GetWeakPtr()),
+          &favicon_task_tracker_);
 }
 
 void AddToHomescreenDataFetcher::OnFaviconFetched(
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
index a0c8d8a..bfd5b05 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
@@ -11,7 +11,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/common/chrome_render_frame.mojom.h"
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
index 3e73052b..8691ac5 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
@@ -25,8 +25,8 @@
 #include "chrome/browser/web_applications/components/web_application_info.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/webapps/installable/installable_manager.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
diff --git a/chrome/browser/android/webapps/add_to_homescreen_installer.cc b/chrome/browser/android/webapps/add_to_homescreen_installer.cc
index e183925..57d1c22 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_installer.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_installer.cc
@@ -10,7 +10,7 @@
 #include "chrome/android/chrome_jni_headers/AddToHomescreenInstaller_jni.h"
 #include "chrome/browser/android/shortcut_helper.h"
 #include "chrome/browser/android/tab_android.h"
-#include "components/webapps/webapps_client.h"
+#include "components/webapps/browser/webapps_client.h"
 #include "content/public/browser/web_contents.h"
 
 namespace webapps {
diff --git a/chrome/browser/android/webapps/add_to_homescreen_installer.h b/chrome/browser/android/webapps/add_to_homescreen_installer.h
index 7dac3efc..fc111c3 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_installer.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_installer.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_ANDROID_WEBAPPS_ADD_TO_HOMESCREEN_INSTALLER_H_
 
 #include "base/callback_forward.h"
-#include "components/webapps/android/add_to_homescreen_params.h"
+#include "components/webapps/browser/android/add_to_homescreen_params.h"
 
 namespace content {
 class WebContents;
diff --git a/chrome/browser/android/webapps/add_to_homescreen_mediator.cc b/chrome/browser/android/webapps/add_to_homescreen_mediator.cc
index 048327d7..f1b3cb3 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_mediator.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_mediator.cc
@@ -16,9 +16,9 @@
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "components/url_formatter/elide_url.h"
-#include "components/webapps/android/add_to_homescreen_params.h"
-#include "components/webapps/installable/installable_metrics.h"
-#include "components/webapps/webapps_client.h"
+#include "components/webapps/browser/android/add_to_homescreen_params.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
+#include "components/webapps/browser/webapps_client.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/gfx/android/java_bitmap.h"
 
diff --git a/chrome/browser/android/webapps/add_to_homescreen_mediator.h b/chrome/browser/android/webapps/add_to_homescreen_mediator.h
index 0386ec5..7cc45e4 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_mediator.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_mediator.h
@@ -14,7 +14,7 @@
 #include "chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h"
 #include "chrome/browser/android/webapps/add_to_homescreen_installer.h"
 #include "chrome/browser/banners/app_banner_manager.h"
-#include "components/webapps/android/add_to_homescreen_params.h"
+#include "components/webapps/browser/android/add_to_homescreen_params.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/banners/android/BUILD.gn b/chrome/browser/banners/android/BUILD.gn
index 8fac3ef..871de95 100644
--- a/chrome/browser/banners/android/BUILD.gn
+++ b/chrome/browser/banners/android/BUILD.gn
@@ -24,7 +24,7 @@
     "//chrome/browser/ui/android/appmenu:java",
     "//chrome/browser/user_education:java",
     "//components/feature_engagement/public:public_java",
-    "//components/webapps/android:java",
+    "//components/webapps/browser/android:java",
     "//content/public/android:content_java",
     "//third_party/android_deps:androidx_annotation_annotation_java",
     "//ui/android:ui_no_recycler_view_java",
@@ -72,7 +72,7 @@
     "//components/signin/core/browser/android:java",
     "//components/signin/core/browser/android:signin_java_test_support",
     "//components/site_engagement/content/android:java",
-    "//components/webapps/android:java",
+    "//components/webapps/browser/android:java",
     "//content/public/android:content_java",
     "//content/public/test/android:content_java_test_support",
     "//net/android:net_java_test_support",
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index 4038272c..6570e199 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -21,9 +21,9 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/site_engagement/content/site_engagement_service.h"
-#include "components/webapps/installable/installable_data.h"
-#include "components/webapps/installable/installable_manager.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h
index e00b47d..b342c9f 100644
--- a/chrome/browser/banners/app_banner_manager.h
+++ b/chrome/browser/banners/app_banner_manager.h
@@ -14,8 +14,8 @@
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
 #include "components/site_engagement/content/site_engagement_observer.h"
-#include "components/webapps/installable/installable_logging.h"
-#include "components/webapps/installable/installable_params.h"
+#include "components/webapps/browser/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_params.h"
 #include "content/public/browser/media_player_id.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/chrome/browser/banners/app_banner_manager_android.cc b/chrome/browser/banners/app_banner_manager_android.cc
index e39498444..18b541c 100644
--- a/chrome/browser/banners/app_banner_manager_android.cc
+++ b/chrome/browser/banners/app_banner_manager_android.cc
@@ -32,13 +32,13 @@
 #include "components/infobars/core/infobar_delegate.h"
 #include "components/site_engagement/content/site_engagement_service.h"
 #include "components/version_info/channel.h"
-#include "components/webapps/android/add_to_homescreen_params.h"
-#include "components/webapps/android/shortcut_info.h"
-#include "components/webapps/android/webapps_icon_utils.h"
-#include "components/webapps/android/webapps_utils.h"
-#include "components/webapps/installable/installable_data.h"
-#include "components/webapps/installable/installable_metrics.h"
-#include "components/webapps/webapps_client.h"
+#include "components/webapps/browser/android/add_to_homescreen_params.h"
+#include "components/webapps/browser/android/shortcut_info.h"
+#include "components/webapps/browser/android/webapps_icon_utils.h"
+#include "components/webapps/browser/android/webapps_utils.h"
+#include "components/webapps/browser/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
+#include "components/webapps/browser/webapps_client.h"
 #include "content/public/browser/manifest_icon_downloader.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/url_util.h"
diff --git a/chrome/browser/banners/app_banner_manager_android.h b/chrome/browser/banners/app_banner_manager_android.h
index ea498b698..3975111e 100644
--- a/chrome/browser/banners/app_banner_manager_android.h
+++ b/chrome/browser/banners/app_banner_manager_android.h
@@ -15,7 +15,7 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/android/webapps/add_to_homescreen_installer.h"
 #include "chrome/browser/banners/app_banner_manager.h"
-#include "components/webapps/android/installable/installable_ambient_badge_infobar_delegate.h"
+#include "components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc
index 9c18678c..c601dd0 100644
--- a/chrome/browser/banners/app_banner_manager_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -25,9 +25,9 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/site_engagement/content/site_engagement_score.h"
 #include "components/site_engagement/content/site_engagement_service.h"
-#include "components/webapps/installable/installable_logging.h"
-#include "components/webapps/installable/installable_manager.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 
diff --git a/chrome/browser/banners/app_banner_metrics.cc b/chrome/browser/banners/app_banner_metrics.cc
index 540f8e8..17a4779 100644
--- a/chrome/browser/banners/app_banner_metrics.cc
+++ b/chrome/browser/banners/app_banner_metrics.cc
@@ -6,7 +6,7 @@
 
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "components/webapps/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_logging.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 
 namespace webapps {
diff --git a/chrome/browser/banners/app_banner_metrics.h b/chrome/browser/banners/app_banner_metrics.h
index 9ac49460..b9ebb2d 100644
--- a/chrome/browser/banners/app_banner_metrics.h
+++ b/chrome/browser/banners/app_banner_metrics.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_BANNERS_APP_BANNER_METRICS_H_
 #define CHROME_BROWSER_BANNERS_APP_BANNER_METRICS_H_
 
-#include "components/webapps/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_logging.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom-forward.h"
 
 namespace webapps {
diff --git a/chrome/browser/banners/test_app_banner_manager_desktop.cc b/chrome/browser/banners/test_app_banner_manager_desktop.cc
index a3305727..2d85d49 100644
--- a/chrome/browser/banners/test_app_banner_manager_desktop.cc
+++ b/chrome/browser/banners/test_app_banner_manager_desktop.cc
@@ -9,7 +9,7 @@
 
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "components/webapps/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_data.h"
 #include "content/public/browser/web_contents.h"
 
 namespace webapps {
diff --git a/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc b/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc
index 09d05d0a..18c062e 100644
--- a/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc
+++ b/chrome/browser/chrome_web_platform_security_metrics_browsertest.cc
@@ -280,6 +280,72 @@
   ExpectHistogramIncreasedBy(1);
 }
 
+// Check kEmbeddedCrossOriginFrameWithoutFrameAncestorsOrXFO feature usage.
+// This should increment in cases where a cross-origin frame is embedded which
+// does not assert either X-Frame-Options or CSP's frame-ancestors.
+IN_PROC_BROWSER_TEST_F(ChromeWebPlatformSecurityMetricsBrowserTest,
+                       EmbeddingOptIn) {
+  set_monitored_feature(
+      blink::mojom::WebFeature::
+          kEmbeddedCrossOriginFrameWithoutFrameAncestorsOrXFO);
+  GURL main_document_url = https_server().GetURL("a.com", "/title1.html");
+
+  struct TestCase {
+    const char* name;
+    const char* host;
+    const char* header;
+    bool expect_counter;
+  } cases[] = {{
+                   "Same-origin, no XFO, no frame-ancestors",
+                   "a.com",
+                   nullptr,
+                   false,
+               },
+               {
+                   "Cross-origin, no XFO, no frame-ancestors",
+                   "b.com",
+                   nullptr,
+                   true,
+               },
+               {
+                   "Same-origin, yes XFO, no frame-ancestors",
+                   "a.com",
+                   "X-Frame-Options: ALLOWALL",
+                   false,
+               },
+               {
+                   "Cross-origin, yes XFO, no frame-ancestors",
+                   "b.com",
+                   "X-Frame-Options: ALLOWALL",
+                   false,
+               },
+               {
+                   "Same-origin, no XFO, yes frame-ancestors",
+                   "a.com",
+                   "Content-Security-Policy: frame-ancestors *",
+                   false,
+               },
+               {
+                   "Cross-origin, no XFO, yes frame-ancestors",
+                   "b.com",
+                   "Content-Security-Policy: frame-ancestors *",
+                   false,
+               }};
+
+  for (auto test : cases) {
+    SCOPED_TRACE(test.name);
+    EXPECT_TRUE(content::NavigateToURL(web_contents(), main_document_url));
+
+    std::string path = "/set-header?";
+    if (test.header)
+      path += test.header;
+    GURL url = https_server().GetURL(test.host, path);
+    LoadIFrame(url);
+
+    ExpectHistogramIncreasedBy(test.expect_counter ? 1 : 0);
+  }
+}
+
 // TODO(arthursonzogni): Add basic test(s) for the WebFeatures:
 // - CrossOriginOpenerPolicySameOrigin
 // - CrossOriginOpenerPolicySameOriginAllowPopups
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 3523ee4d..8060e41 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -354,7 +354,7 @@
 
     # TODO: care about enable_basic_printing and enable_print_preview.
     "//ash/keyboard/ui",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//printing",
     "//printing/mojom",
     "//remoting/host/it2me:chrome_os_host",
diff --git a/chrome/browser/chromeos/accessibility/dictation_chromeos.cc b/chrome/browser/chromeos/accessibility/dictation_chromeos.cc
index 9904ab8..d92efe9ab 100644
--- a/chrome/browser/chromeos/accessibility/dictation_chromeos.cc
+++ b/chrome/browser/chromeos/accessibility/dictation_chromeos.cc
@@ -138,7 +138,9 @@
 
     ui::IMEInputContextHandlerInterface* input_context = GetInputContext();
     if (input_context)
-      input_context->CommitText(base::UTF16ToUTF8(composition_->text));
+      input_context->CommitText(
+          base::UTF16ToUTF8(composition_->text),
+          ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
 
     composition_->text = base::string16();
   } else {
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
index f5b030e..092d6e0 100644
--- a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
@@ -164,12 +164,8 @@
 };
 
 // The status tray is not active on official builds.
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-#define MAYBE_SpeakStatusTray DISABLED_SpeakStatusTray
-#else
-#define MAYBE_SpeakStatusTray SpeakStatusTray
-#endif
-IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, MAYBE_SpeakStatusTray) {
+// Disable the test on Chromium due to flaky: crbug.com/1165749
+IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, DISABLED_SpeakStatusTray) {
   gfx::Rect tray_bounds = ash::Shell::Get()
                               ->GetPrimaryRootWindowController()
                               ->GetStatusAreaWidget()
diff --git a/chrome/browser/chromeos/apps/apk_web_app_installer.cc b/chrome/browser/chromeos/apps/apk_web_app_installer.cc
index e6366bfa..07fb5b6d 100644
--- a/chrome/browser/chromeos/apps/apk_web_app_installer.cc
+++ b/chrome/browser/chromeos/apps/apk_web_app_installer.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/browser_thread.h"
 #include "services/data_decoder/public/cpp/decode_image.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.cc
index 97031cf..c2eb8b1 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.cc
@@ -51,7 +51,7 @@
 CertProvisioningInvalidationHandler::BuildAndRegister(
     CertScope scope,
     invalidation::InvalidationService* invalidation_service,
-    const syncer::Topic& topic,
+    const invalidation::Topic& topic,
     OnInvalidationCallback on_invalidation_callback) {
   auto invalidator = std::make_unique<CertProvisioningInvalidationHandler>(
       scope, invalidation_service, topic, std::move(on_invalidation_callback));
@@ -66,7 +66,7 @@
 CertProvisioningInvalidationHandler::CertProvisioningInvalidationHandler(
     CertScope scope,
     invalidation::InvalidationService* invalidation_service,
-    const syncer::Topic& topic,
+    const invalidation::Topic& topic,
     OnInvalidationCallback on_invalidation_callback)
     : scope_(scope),
       invalidation_service_(invalidation_service),
@@ -109,8 +109,8 @@
   // Assuming that updating invalidator's topics with empty set can never fail
   // since failure is only possible non-empty set with topic associated with
   // some other invalidator.
-  const bool topics_reset =
-      invalidation_service_->UpdateInterestedTopics(this, syncer::TopicSet());
+  const bool topics_reset = invalidation_service_->UpdateInterestedTopics(
+      this, invalidation::TopicSet());
   DCHECK(topics_reset);
   invalidation_service_observer_.Remove(invalidation_service_);
 
@@ -118,22 +118,22 @@
 }
 
 void CertProvisioningInvalidationHandler::OnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
+    invalidation::InvalidatorState state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   state_.is_invalidation_service_enabled =
-      state == syncer::INVALIDATIONS_ENABLED;
+      state == invalidation::INVALIDATIONS_ENABLED;
 }
 
 void CertProvisioningInvalidationHandler::OnIncomingInvalidation(
-    const syncer::TopicInvalidationMap& invalidation_map) {
+    const invalidation::TopicInvalidationMap& invalidation_map) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!state_.is_invalidation_service_enabled) {
     LOG(WARNING) << "Unexpected invalidation received.";
   }
 
-  const syncer::SingleObjectInvalidationSet& list =
+  const invalidation::SingleObjectInvalidationSet& list =
       invalidation_map.ForTopic(topic_);
   if (list.IsEmpty()) {
     NOTREACHED() << "Incoming invlaidation does not contain invalidation"
@@ -154,7 +154,7 @@
 }
 
 bool CertProvisioningInvalidationHandler::IsPublicTopic(
-    const syncer::Topic& topic) const {
+    const invalidation::Topic& topic) const {
   return base::StartsWith(topic, kFcmCertProvisioningPublicTopicPrefix,
                           base::CompareCase::SENSITIVE);
 }
@@ -195,7 +195,7 @@
 }
 
 void CertProvisioningUserInvalidator::Register(
-    const syncer::Topic& topic,
+    const invalidation::Topic& topic,
     OnInvalidationCallback on_invalidation_callback) {
   invalidation::ProfileInvalidationProvider* invalidation_provider =
       invalidation::ProfileInvalidationProviderFactory::GetForProfile(profile_);
@@ -241,7 +241,7 @@
 }
 
 void CertProvisioningDeviceInvalidator::Register(
-    const syncer::Topic& topic,
+    const invalidation::Topic& topic,
     OnInvalidationCallback on_invalidation_callback) {
   topic_ = topic;
   on_invalidation_callback_ = std::move(on_invalidation_callback);
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.h b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.h
index 903abcb..78e944d9 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.h
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator.h
@@ -33,7 +33,8 @@
 // topic when destroyed so that subscription can be preserved if browser
 // restarts. A user must explicitly call |Unregister| if subscription is not
 // needed anymore.
-class CertProvisioningInvalidationHandler : public syncer::InvalidationHandler {
+class CertProvisioningInvalidationHandler
+    : public invalidation::InvalidationHandler {
  public:
   // Creates and registers the handler to |invalidation_service| with |topic|.
   // |on_invalidation_callback| will be called when incoming invalidation is
@@ -42,13 +43,13 @@
   static std::unique_ptr<CertProvisioningInvalidationHandler> BuildAndRegister(
       CertScope scope,
       invalidation::InvalidationService* invalidation_service,
-      const syncer::Topic& topic,
+      const invalidation::Topic& topic,
       OnInvalidationCallback on_invalidation_callback);
 
   CertProvisioningInvalidationHandler(
       CertScope scope,
       invalidation::InvalidationService* invalidation_service,
-      const syncer::Topic& topic,
+      const invalidation::Topic& topic,
       OnInvalidationCallback on_invalidation_callback);
   CertProvisioningInvalidationHandler(
       const CertProvisioningInvalidationHandler&) = delete;
@@ -60,12 +61,12 @@
   // Unregisters handler and unsubscribes given topic from invalidation service.
   void Unregister();
 
-  // syncer::InvalidationHandler:
-  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  // invalidation::InvalidationHandler:
+  void OnInvalidatorStateChange(invalidation::InvalidatorState state) override;
   void OnIncomingInvalidation(
-      const syncer::TopicInvalidationMap& invalidation_map) override;
+      const invalidation::TopicInvalidationMap& invalidation_map) override;
   std::string GetOwnerName() const override;
-  bool IsPublicTopic(const syncer::Topic& topic) const override;
+  bool IsPublicTopic(const invalidation::Topic& topic) const override;
 
  private:
   // Registers the handler to |invalidation_service_| and subscribes with
@@ -91,13 +92,13 @@
 
   ScopedObserver<
       invalidation::InvalidationService,
-      syncer::InvalidationHandler,
+      invalidation::InvalidationHandler,
       &invalidation::InvalidationService::RegisterInvalidationHandler,
       &invalidation::InvalidationService::UnregisterInvalidationHandler>
       invalidation_service_observer_{this};
 
   // A topic representing certificate invalidations.
-  const syncer::Topic topic_;
+  const invalidation::Topic topic_;
 
   // A callback to be called on incoming invalidation event.
   const OnInvalidationCallback on_invalidation_callback_;
@@ -139,7 +140,7 @@
       delete;
   virtual ~CertProvisioningInvalidator();
 
-  virtual void Register(const syncer::Topic& topic,
+  virtual void Register(const invalidation::Topic& topic,
                         OnInvalidationCallback on_invalidation_callback) = 0;
   virtual void Unregister();
 
@@ -168,7 +169,7 @@
  public:
   explicit CertProvisioningUserInvalidator(Profile* profile);
 
-  void Register(const syncer::Topic& topic,
+  void Register(const invalidation::Topic& topic,
                 OnInvalidationCallback on_invalidation_callback) override;
 
  private:
@@ -200,7 +201,7 @@
       policy::AffiliatedInvalidationServiceProvider* service_provider);
   ~CertProvisioningDeviceInvalidator() override;
 
-  void Register(const syncer::Topic& topic,
+  void Register(const invalidation::Topic& topic,
                 OnInvalidationCallback on_invalidation_callback) override;
   void Unregister() override;
 
@@ -209,7 +210,7 @@
   void OnInvalidationServiceSet(
       invalidation::InvalidationService* invalidation_service) override;
 
-  syncer::Topic topic_;
+  invalidation::Topic topic_;
   OnInvalidationCallback on_invalidation_callback_;
   policy::AffiliatedInvalidationServiceProvider* service_provider_ = nullptr;
 };
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator_unittest.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator_unittest.cc
index 0960b13..6cc5aec 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator_unittest.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_invalidator_unittest.cc
@@ -53,30 +53,34 @@
   }
 
   void EnableInvalidationService() {
-    invalidation_service_.SetInvalidatorState(syncer::INVALIDATIONS_ENABLED);
+    invalidation_service_.SetInvalidatorState(
+        invalidation::INVALIDATIONS_ENABLED);
   }
 
   void DisableInvalidationService() {
     invalidation_service_.SetInvalidatorState(
-        syncer::TRANSIENT_INVALIDATION_ERROR);
+        invalidation::TRANSIENT_INVALIDATION_ERROR);
   }
 
-  syncer::Invalidation CreateInvalidation(const syncer::Topic& topic) {
-    return syncer::Invalidation::InitUnknownVersion(topic);
+  invalidation::Invalidation CreateInvalidation(
+      const invalidation::Topic& topic) {
+    return invalidation::Invalidation::InitUnknownVersion(topic);
   }
 
-  syncer::Invalidation FireInvalidation(const syncer::Topic& topic) {
-    const syncer::Invalidation invalidation = CreateInvalidation(topic);
+  invalidation::Invalidation FireInvalidation(
+      const invalidation::Topic& topic) {
+    const invalidation::Invalidation invalidation = CreateInvalidation(topic);
     invalidation_service_.EmitInvalidationForTest(invalidation);
     base::RunLoop().RunUntilIdle();
     return invalidation;
   }
 
-  bool IsInvalidationSent(const syncer::Invalidation& invalidation) {
+  bool IsInvalidationSent(const invalidation::Invalidation& invalidation) {
     return !invalidation_service_.GetMockAckHandler()->IsUnsent(invalidation);
   }
 
-  bool IsInvalidationAcknowledged(const syncer::Invalidation& invalidation) {
+  bool IsInvalidationAcknowledged(
+      const invalidation::Invalidation& invalidation) {
     return invalidation_service_.GetMockAckHandler()->IsAcknowledged(
         invalidation);
   }
@@ -96,8 +100,8 @@
 
   base::test::SingleThreadTaskEnvironment task_environment_;
 
-  const syncer::Topic kInvalidatorTopic;
-  const syncer::Topic kSomeOtherTopic;
+  const invalidation::Topic kInvalidatorTopic;
+  const invalidation::Topic kSomeOtherTopic;
 
   invalidation::FakeInvalidationService invalidation_service_;
 
@@ -180,7 +184,7 @@
   EXPECT_EQ(0, incoming_invalidations_count_);
 
   // Ensure that topic is still subscribed.
-  const syncer::Topics topics =
+  const invalidation::Topics topics =
       invalidation_service_.invalidator_registrar().GetAllSubscribedTopics();
   EXPECT_NE(topics.end(), topics.find(kInvalidatorTopic));
 }
diff --git a/chrome/browser/chromeos/cert_provisioning/mock_cert_provisioning_invalidator.h b/chrome/browser/chromeos/cert_provisioning/mock_cert_provisioning_invalidator.h
index f67499b..01e7d49c 100644
--- a/chrome/browser/chromeos/cert_provisioning/mock_cert_provisioning_invalidator.h
+++ b/chrome/browser/chromeos/cert_provisioning/mock_cert_provisioning_invalidator.h
@@ -32,7 +32,7 @@
 
   MOCK_METHOD(void,
               Register,
-              (const syncer::Topic& topic,
+              (const invalidation::Topic& topic,
                OnInvalidationCallback on_invalidation_callback),
               (override));
 
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper_unittest.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper_unittest.cc
index e8cbce532..2f94f6d 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper_unittest.cc
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper_unittest.cc
@@ -42,7 +42,7 @@
 #include "components/arc/test/fake_app_instance.h"
 #include "components/services/app_service/public/cpp/app_update.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/common/constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
index 3d5fe45..57218f1 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/common/extensions/api/omnibox.h"
 #include "chrome/grit/generated_resources.h"
 #include "extensions/browser/device_local_account_util.h"
 #include "extensions/common/api/incognito.h"
@@ -185,7 +186,7 @@
     // A bit risky as the extensions sees all keystrokes entered into the
     // omnibox after the search key matches, but generally we deem URLs fair
     // game.
-    emk::kOmnibox,
+    ::extensions::api::omnibox::ManifestKeys::kOmnibox,
 
     // Special-cased in IsSafeForPublicSession(). Subject to permission
     // restrictions.
diff --git a/chrome/browser/chromeos/input_method/autocorrect_manager.cc b/chrome/browser/chromeos/input_method/autocorrect_manager.cc
index e3902b0..84d610d 100644
--- a/chrome/browser/chromeos/input_method/autocorrect_manager.cc
+++ b/chrome/browser/chromeos/input_method/autocorrect_manager.cc
@@ -214,7 +214,8 @@
   input_context->CommitText(
       (base::UTF16ToUTF8(
            surrounding_text.surrounding_text.substr(0, range.start())) +
-       original_text_));
+       original_text_),
+      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   LogAssistiveAutocorrectAction(AutocorrectActions::kReverted);
   RecordAssistiveCoverage(AssistiveType::kAutocorrectReverted);
   RecordAssistiveSuccess(AssistiveType::kAutocorrectReverted);
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc
index d4ed6ad7..bccb2ce 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine.cc
@@ -502,7 +502,9 @@
     return;
 
   const bool had_composition_text = input_context->HasCompositionText();
-  input_context->CommitText(text);
+  input_context->CommitText(
+      text,
+      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
 
   if (had_composition_text) {
     // Records histograms for committed characters with composition text.
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine.cc b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
index b7f492b..16bbbfc 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
@@ -412,7 +412,9 @@
 }
 
 void NativeInputMethodEngine::ImeObserver::CommitText(const std::string& text) {
-  GetInputContext()->CommitText(NormalizeString(text));
+  GetInputContext()->CommitText(
+      NormalizeString(text),
+      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
 }
 
 void NativeInputMethodEngine::ImeObserver::SetComposition(
@@ -491,7 +493,10 @@
   for (const auto& op : response->operations) {
     switch (op->method) {
       case ime::mojom::OperationMethodForRulebased::COMMIT_TEXT:
-        GetInputContext()->CommitText(NormalizeString(op->arguments));
+        GetInputContext()->CommitText(
+            NormalizeString(op->arguments),
+            ui::TextInputClient::InsertTextCursorBehavior::
+                kMoveCursorAfterText);
         break;
       case ime::mojom::OperationMethodForRulebased::SET_COMPOSITION:
         ui::CompositionText composition;
diff --git a/chrome/browser/chromeos/login/login_auth_recorder.cc b/chrome/browser/chromeos/login/login_auth_recorder.cc
index 841fd9b5..d99b7ac 100644
--- a/chrome/browser/chromeos/login/login_auth_recorder.cc
+++ b/chrome/browser/chromeos/login/login_auth_recorder.cc
@@ -136,19 +136,29 @@
 
 void LoginAuthRecorder::RecordAuthMethod(AuthMethod method) {
   DCHECK_NE(method, AuthMethod::kNothing);
-  if (session_manager::SessionManager::Get()->session_state() !=
-      session_manager::SessionState::LOCKED) {
-    return;
-  }
 
-  // Record usage of the authentication method in lock screen.
+  bool is_locked;
+  switch (session_manager::SessionManager::Get()->session_state()) {
+    case session_manager::SessionState::LOGIN_PRIMARY:
+    case session_manager::SessionState::LOGIN_SECONDARY:
+      is_locked = false;
+      break;
+    case session_manager::SessionState::LOCKED:
+      is_locked = true;
+      break;
+    default:
+      return;
+  }
+  const std::string prefix =
+      is_locked ? "Ash.Login.Lock.AuthMethod." : "Ash.Login.Login.AuthMethod.";
+
+  // Record usage of the authentication method in login/lock screen.
   const bool is_tablet_mode = ash::TabletMode::Get()->InTabletMode();
+  std::string used_metric_name;
   if (is_tablet_mode) {
-    base::UmaHistogramEnumeration("Ash.Login.Lock.AuthMethod.Used.TabletMode",
-                                  method);
+    base::UmaHistogramEnumeration(prefix + "Used.TabletMode", method);
   } else {
-    base::UmaHistogramEnumeration(
-        "Ash.Login.Lock.AuthMethod.Used.ClamShellMode", method);
+    base::UmaHistogramEnumeration(prefix + "Used.ClamShellMode", method);
   }
 
   if (last_auth_method_ != method) {
@@ -156,8 +166,7 @@
     const base::Optional<AuthMethodSwitchType> switch_type =
         FindSwitchType(last_auth_method_, method);
     if (switch_type) {
-      base::UmaHistogramEnumeration("Ash.Login.Lock.AuthMethod.Switched",
-                                    *switch_type);
+      base::UmaHistogramEnumeration(prefix + "Switched", *switch_type);
     }
 
     last_auth_method_ = method;
diff --git a/chrome/browser/chromeos/login/login_pref_names.cc b/chrome/browser/chromeos/login/login_pref_names.cc
index 12ff88c6..fbd7db133 100644
--- a/chrome/browser/chromeos/login/login_pref_names.cc
+++ b/chrome/browser/chromeos/login/login_pref_names.cc
@@ -15,6 +15,14 @@
 // Last input user method which could be used on the login/lock screens.
 const char kLastLoginInputMethod[] = "login.last_input_method";
 
+// A boolean pref to indicate if the marketing opt-in screen in OOBE is finished
+// for the user.
+const char kOobeMarketingOptInScreenFinished[] =
+    "OobeMarketingOptInScreenFinished";
+
+// Whether the user has chosen to sign up for marketing emails.
+const char kOobeMarketingOptInChoice[] = "OobeMarketingOptInChoice";
+
 // Time when new user has finished onboarding.
 const char kOobeOnboardingTime[] = "oobe.onboarding_time";
 
@@ -51,6 +59,14 @@
 // SAML password sync token fetched from the external API.
 const char kSamlPasswordSyncToken[] = "saml.password_sync_token";
 
+// *************** OOBE LOCAL STATE PREFS ***************
+
+// A boolean pref of the OOBE complete flag (first OOBE part before login).
+const char kOobeComplete[] = "OobeComplete";
+
+// The name of the screen that has to be shown if OOBE has been interrupted.
+const char kOobeScreenPending[] = "OobeScreenPending";
+
 }  // namespace prefs
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_pref_names.h b/chrome/browser/chromeos/login/login_pref_names.h
index a853db0..1e6b0e5 100644
--- a/chrome/browser/chromeos/login/login_pref_names.h
+++ b/chrome/browser/chromeos/login/login_pref_names.h
@@ -10,7 +10,11 @@
 namespace prefs {
 
 extern const char kLastLoginInputMethod[];
+extern const char kOobeComplete[];
 extern const char kOobeOnboardingTime[];
+extern const char kOobeMarketingOptInScreenFinished[];
+extern const char kOobeMarketingOptInChoice[];
+extern const char kOobeScreenPending[];
 extern const char kSAMLOfflineSigninTimeLimit[];
 extern const char kSAMLLastGAIASignInTime[];
 extern const char kSamlInSessionPasswordChangeEnabled[];
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index bb12ec72..6f4de35 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/test/session_manager_state_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host_webui.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
diff --git a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
index 657227f..b7be7ed 100644
--- a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
+++ b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.cc
@@ -17,11 +17,13 @@
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/apps/user_type_filter.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/login/marketing_backend_connector.h"
 #include "chrome/browser/chromeos/login/screen_manager.h"
 #include "chrome/browser/chromeos/login/screens/gesture_navigation_screen.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager_util.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/gesture_navigation_screen_handler.h"
@@ -29,8 +31,10 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/prefs/pref_service.h"
+#include "components/sync_preferences/pref_service_syncable.h"
 #include "third_party/icu/source/common/unicode/utypes.h"
 #include "third_party/icu/source/i18n/unicode/timezone.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -102,9 +106,11 @@
 }
 
 bool MarketingOptInScreen::MaybeSkip(WizardContext* context) {
-  if (!base::FeatureList::IsEnabled(features::kOobeMarketingScreen) ||
+  Initialize();
+
+  if (!base::FeatureList::IsEnabled(::features::kOobeMarketingScreen) ||
       chrome_user_manager_util::IsPublicSessionOrEphemeralLogin() ||
-      IsCurrentUserManaged() /*skip for enterprise and supervised users*/) {
+      IsCurrentUserManaged()) {
     exit_callback_.Run(Result::NOT_APPLICABLE);
     return true;
   }
@@ -113,25 +119,19 @@
 }
 
 void MarketingOptInScreen::ShowImpl() {
+  DCHECK(initialized_);
+
+  // Show a verbose legal footer for Canada. (https://crbug.com/1124956)
+  const bool legal_footer_visible =
+      email_opt_in_visible_ && countries_with_legal_footer.count(country_);
+
+  view_->Show(/*opt_in_visible=*/email_opt_in_visible_,
+              /*opt_in_default_state=*/IsDefaultOptInCountry(),
+              /*legal_footer_visible=*/legal_footer_visible);
+
+  // Mark the screen as shown for this user.
   PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
-
-  // Set the country to be used based on the timezone
-  // and supported country list.
-  SetCountryFromTimezoneIfAvailable(g_browser_process->local_state()->GetString(
-      prefs::kSigninScreenTimezone));
-
-  view_->Show();
-
-  // Hide the marketing opt-in option if:
-  //   1) the user is managed. (enterprise-managed, guest, child, supervised)
-  // OR
-  //   2) The country is not a supported country. (empty)
-  //
-  email_opt_in_visible_ = !(IsCurrentUserManaged() || (country_.empty()));
-  view_->SetOptInVisibility(email_opt_in_visible_);
-
-  // Set the default state of the email opt-in toggle.
-  view_->SetEmailToggleState(IsDefaultOptInCountry());
+  prefs->SetBoolean(prefs::kOobeMarketingOptInScreenFinished, true);
 
   // Only show the link for accessibility settings if the gesture navigation
   // screen was shown.
@@ -164,15 +164,20 @@
 }
 
 void MarketingOptInScreen::OnGetStarted(bool chromebook_email_opt_in) {
-  Profile* profile = ProfileManager::GetPrimaryUserProfile();
+  DCHECK(initialized_);
 
   // UMA Metrics & API call only when the toggle is visible
   if (email_opt_in_visible_) {
-    RecordOptInAndOptOutRates(chromebook_email_opt_in /*user_opted_in*/,
-                              IsDefaultOptInCountry() /*opt_in_by_default*/,
-                              country_ /*country*/);
+    RecordOptInAndOptOutRates(/*user_opted_in=*/chromebook_email_opt_in,
+                              /*opt_in_by_default=*/IsDefaultOptInCountry(),
+                              /*country=*/country_);
 
-    if ((profile != nullptr) && chromebook_email_opt_in) {
+    // Store the user's preference regarding marketing emails
+    Profile* profile = ProfileManager::GetActiveUserProfile();
+    DCHECK(profile);
+    profile->GetPrefs()->SetBoolean(prefs::kOobeMarketingOptInChoice,
+                                    chromebook_email_opt_in);
+    if (chromebook_email_opt_in) {
       // Call Chromebook Email Service API
       MarketingBackendConnector::UpdateEmailPreferences(profile, country_);
     }
@@ -192,13 +197,26 @@
 }
 
 bool MarketingOptInScreen::IsCurrentUserManaged() {
-  Profile* profile = ProfileManager::GetPrimaryUserProfile();
+  Profile* profile = ProfileManager::GetActiveUserProfile();
   if (profile->IsOffTheRecord())
     return false;
   const std::string user_type = apps::DetermineUserType(profile);
   return (user_type != apps::kUserTypeUnmanaged);
 }
 
+void MarketingOptInScreen::Initialize() {
+  // Set the country to be used based on the timezone
+  // and supported country list.
+  SetCountryFromTimezoneIfAvailable(g_browser_process->local_state()->GetString(
+      ::prefs::kSigninScreenTimezone));
+
+  // Only show the opt in option if this is a supported region, and if the user
+  // never made a choice regarding emails.
+  email_opt_in_visible_ = !country_.empty() && ShouldShowOptionToSubscribe();
+
+  initialized_ = true;
+}
+
 void MarketingOptInScreen::SetCountryFromTimezoneIfAvailable(
     const std::string& timezone_id) {
   // Determine region code from timezone id.
@@ -224,15 +242,42 @@
   const bool is_extended_country =
       additional_countries_.count(region_str) &&
       base::FeatureList::IsEnabled(
-          features::kOobeMarketingAdditionalCountriesSupported);
+          ::features::kOobeMarketingAdditionalCountriesSupported);
   const bool is_double_optin_country =
       double_opt_in_countries_.count(region_str) &&
       base::FeatureList::IsEnabled(
-          features::kOobeMarketingDoubleOptInCountriesSupported);
+          ::features::kOobeMarketingDoubleOptInCountriesSupported);
 
   if (is_default_country || is_extended_country || is_double_optin_country) {
     country_ = region_str;
   }
 }
 
+bool MarketingOptInScreen::ShouldShowOptionToSubscribe() {
+  // Directly access PrefServiceSyncable instead of PrefService because
+  // we need to know whether the prefs have been loaded.
+  sync_preferences::PrefServiceSyncable* prefs =
+      PrefServiceSyncableFromProfile(ProfileManager::GetActiveUserProfile());
+  const bool sync_complete =
+      ignore_pref_sync_for_testing_ ||
+      (features::IsSplitSettingsSyncEnabled() ? prefs->AreOsPrefsSyncing()
+                                              : prefs->IsSyncing());
+  // Do not show if the preferences cannot be synced
+  if (!sync_complete)
+    return false;
+
+  // Show if the screen was never shown before.
+  if (!prefs->GetBoolean(prefs::kOobeMarketingOptInScreenFinished))
+    return true;
+
+  // Show if we haven't recorded the user's choice yet. The screen was shown
+  // in the past, but the option to sign up was not (due to not being
+  // available in the user's region).
+  if (prefs->FindPreference(prefs::kOobeMarketingOptInChoice)->IsDefaultValue())
+    return true;
+
+  // The screen was shown before and the user has made its choice.
+  return false;
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.h b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.h
index 9b5025e..9c574ee 100644
--- a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.h
+++ b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen.h
@@ -9,6 +9,7 @@
 #include <unordered_set>
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
@@ -64,6 +65,10 @@
     exit_callback_ = exit_callback;
   }
 
+  void set_ingore_pref_sync_for_testing(bool ignore_sync) {
+    ignore_pref_sync_for_testing_ = ignore_sync;
+  }
+
   const ScreenExitCallback& get_exit_callback_for_testing() {
     return exit_callback_;
   }
@@ -80,9 +85,17 @@
   // Checks whether this user is managed.
   bool IsCurrentUserManaged();
 
+  // Initializes the screen and determines if it should be visible based on the
+  // country.
+  void Initialize();
+
   // Sets the country to be used if the feature is available in this region.
   void SetCountryFromTimezoneIfAvailable(const std::string& timezone_id);
 
+  // Whether the screen should be shown depending if it was shown before and if
+  // the user had the option to subscribe to emails.
+  bool ShouldShowOptionToSubscribe();
+
   bool IsDefaultOptInCountry() {
     return default_opt_in_countries_.count(country_);
   }
@@ -97,20 +110,32 @@
   // Country code. Unknown IFF empty.
   std::string country_;
 
+  // Whether the screen has been initialized. Determines the country based on
+  // the available geolocation information and whether the screen will support
+  // showing the toggle.
+  bool initialized_ = false;
+
+  // Set by tests so that the sync status of preferences does not interfere when
+  // showing the opt-in option.
+  bool ignore_pref_sync_for_testing_ = false;
+
   // Default country list.
-  const std::unordered_set<std::string> default_countries_{"us", "ca", "gb"};
+  const base::flat_set<base::StringPiece> default_countries_{"us", "ca", "gb"};
 
   // Extended country list. Protected behind the flag:
   // - kOobeMarketingAdditionalCountriesSupported (DEFAULT_ON)
-  const std::unordered_set<std::string> additional_countries_{
+  const base::flat_set<base::StringPiece> additional_countries_{
       "fr", "nl", "fi", "se", "no", "dk", "es", "it", "jp", "au"};
 
   // Countries with double opt-in.  Behind the flag:
   // - kOobeMarketingDoubleOptInCountriesSupported (DEFAULT_OFF)
-  const std::unordered_set<std::string> double_opt_in_countries_{"de"};
+  const base::flat_set<base::StringPiece> double_opt_in_countries_{"de"};
 
   // Countries in which the toggle will be enabled by default.
-  const std::unordered_set<std::string> default_opt_in_countries_{"us"};
+  const base::flat_set<base::StringPiece> default_opt_in_countries_{"us"};
+
+  // Countries that require the screen to show a footer with legal information.
+  const base::flat_set<base::StringPiece> countries_with_legal_footer{"ca"};
 
   base::WeakPtrFactory<MarketingOptInScreen> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(MarketingOptInScreen);
diff --git a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc
index 2a9b2d3..966dc85f 100644
--- a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/login/marketing_backend_connector.h"
 #include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
@@ -51,6 +52,10 @@
                                              "chromebookUpdatesOption"};
 const test::UIPath kChromebookEmailToggleDiv = {"marketing-opt-in",
                                                 "marketing-opt-in-toggle"};
+const test::UIPath kChromebookEmailLegalFooterDiv = {"marketing-opt-in",
+                                                     "legalFooter"};
+const test::UIPath kChromebookEmailAnimation = {"marketing-opt-in",
+                                                "animation"};
 const test::UIPath kMarketingA11yButton = {
     "marketing-opt-in", "marketing-opt-in-accessibility-button"};
 const test::UIPath kMarketingFinalA11yPage = {"marketing-opt-in",
@@ -65,30 +70,31 @@
   const char* country_code;
   bool is_default_opt_in;
   bool is_unknown_country;
+  bool requires_legal_footer;
 };
 
 // Default countries
 const RegionToCodeMap kDefaultCountries[]{
-    {"US", "America/Los_Angeles", "us", true, false},
-    {"Canada", "Canada/Atlantic", "ca", false, false},
-    {"UnitedKingdom", "Europe/London", "gb", false, false}};
+    {"US", "America/Los_Angeles", "us", true, false, false},
+    {"Canada", "Canada/Atlantic", "ca", false, false, true},
+    {"UnitedKingdom", "Europe/London", "gb", false, false, false}};
 
 // Extended region list. Behind feature flag.
 const RegionToCodeMap kExtendedCountries[]{
-    {"France", "Europe/Paris", "fr", false, false},
-    {"Netherlands", "Europe/Amsterdam", "nl", false, false},
-    {"Finland", "Europe/Helsinki", "fi", false, false},
-    {"Sweden", "Europe/Stockholm", "se", false, false},
-    {"Norway", "Europe/Oslo", "no", false, false},
-    {"Denmark", "Europe/Copenhagen", "dk", false, false},
-    {"Spain", "Europe/Madrid", "es", false, false},
-    {"Italy", "Europe/Rome", "it", false, false},
-    {"Japan", "Asia/Tokyo", "jp", false, false},
-    {"Australia", "Australia/Sydney", "au", false, false}};
+    {"France", "Europe/Paris", "fr", false, false, false},
+    {"Netherlands", "Europe/Amsterdam", "nl", false, false, false},
+    {"Finland", "Europe/Helsinki", "fi", false, false, false},
+    {"Sweden", "Europe/Stockholm", "se", false, false, false},
+    {"Norway", "Europe/Oslo", "no", false, false, false},
+    {"Denmark", "Europe/Copenhagen", "dk", false, false, false},
+    {"Spain", "Europe/Madrid", "es", false, false, false},
+    {"Italy", "Europe/Rome", "it", false, false, false},
+    {"Japan", "Asia/Tokyo", "jp", false, false, false},
+    {"Australia", "Australia/Sydney", "au", false, false, false}};
 
 // Double opt-in countries. Behind double opt-in feature flag.
 const RegionToCodeMap kDoubleOptInCountries[]{
-    {"Germany", "Europe/Berlin", "de", false, false}};
+    {"Germany", "Europe/Berlin", "de", false, false, false}};
 
 // Unknown country.
 const RegionToCodeMap kUnknownCountry[]{
@@ -113,16 +119,25 @@
   void ExpectNoOptInOption();
   // Expects that the option to opt-in is visible.
   void ExpectOptInOptionAvailable();
+  // Expects a verbose footer containing legal information.
+  void ExpectLegalFooterVisibility(bool visibility);
   // Expects that the opt-in toggle is visible and unchecked.
   void ExpectOptedOut();
   // Expects that the opt-in toggle is visible and checked.
   void ExpectOptedIn();
+  void ExpectRecordedUserPrefRegardingChoice(bool opted_in);
   // Flips the toggle to opt-in. Only to be called when the toggle is unchecked.
   void OptIn();
+  void OptOut();
 
   void ExpectGeolocationMetric(bool resolved, int length);
   void WaitForScreenExit();
-  void SetUpLocalState() override {}
+
+  // US as default location for non-parameterized tests.
+  void SetUpLocalState() override {
+    g_browser_process->local_state()->SetString(::prefs::kSigninScreenTimezone,
+                                                "America/Los_Angeles");
+  }
 
   // Logs in as a normal user. Overridden by subclasses.
   virtual void PerformLogin();
@@ -182,6 +197,7 @@
   original_callback_ = GetScreen()->get_exit_callback_for_testing();
   GetScreen()->set_exit_callback_for_testing(base::BindRepeating(
       &MarketingOptInScreenTest::HandleScreenExit, base::Unretained(this)));
+  GetScreen()->set_ingore_pref_sync_for_testing(true);
 
   OobeBaseTest::SetUpOnMainThread();
 }
@@ -222,6 +238,17 @@
   test::OobeJS().ExpectVisiblePath(kChromebookEmailToggleDiv);
 }
 
+void MarketingOptInScreenTest::ExpectLegalFooterVisibility(bool visibility) {
+  ExpectOptInOptionAvailable();
+  if (visibility) {
+    test::OobeJS().ExpectVisiblePath(kChromebookEmailLegalFooterDiv);
+    test::OobeJS().ExpectHiddenPath(kChromebookEmailAnimation);
+  } else {
+    test::OobeJS().ExpectHiddenPath(kChromebookEmailLegalFooterDiv);
+    test::OobeJS().ExpectVisiblePath(kChromebookEmailAnimation);
+  }
+}
+
 void MarketingOptInScreenTest::ExpectOptedOut() {
   ExpectOptInOptionAvailable();
   test::OobeJS().ExpectHasNoAttribute("checked", kChromebookEmailToggle);
@@ -232,11 +259,28 @@
   test::OobeJS().ExpectHasAttribute("checked", kChromebookEmailToggle);
 }
 
+void MarketingOptInScreenTest::ExpectRecordedUserPrefRegardingChoice(
+    bool opted_in) {
+  EXPECT_TRUE(
+      ProfileManager::GetPrimaryUserProfile()->GetPrefs()->GetUserPrefValue(
+          prefs::kOobeMarketingOptInChoice) != nullptr);
+  EXPECT_EQ(ProfileManager::GetPrimaryUserProfile()->GetPrefs()->GetBoolean(
+                prefs::kOobeMarketingOptInChoice),
+            opted_in);
+}
+
 void MarketingOptInScreenTest::OptIn() {
+  ExpectOptedOut();
   test::OobeJS().ClickOnPath(kChromebookEmailToggle);
   test::OobeJS().ExpectHasAttribute("checked", kChromebookEmailToggle);
 }
 
+void MarketingOptInScreenTest::OptOut() {
+  ExpectOptedIn();
+  test::OobeJS().ClickOnPath(kChromebookEmailToggle);
+  test::OobeJS().ExpectHasNoAttribute("checked", kChromebookEmailToggle);
+}
+
 void MarketingOptInScreenTest::ExpectGeolocationMetric(bool resolved,
                                                        int length) {
   histogram_tester_.ExpectUniqueSample(
@@ -294,10 +338,85 @@
 
 // Tests that the screen is visible
 IN_PROC_BROWSER_TEST_F(MarketingOptInScreenTest, ScreenVisible) {
-  ShowMarketingOptInScreen();
+  PerformLogin();
+  OobeScreenExitWaiter(GetFirstSigninScreen()).Wait();
+  // Expect the screen to not have been shown before.
+  EXPECT_FALSE(ProfileManager::GetActiveUserProfile()->GetPrefs()->GetBoolean(
+      prefs::kOobeMarketingOptInScreenFinished));
+  LoginDisplayHost::default_host()->StartWizard(
+      MarketingOptInScreenView::kScreenId);
+
   OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
   test::OobeJS().ExpectVisiblePath(
       {"marketing-opt-in", "marketingOptInOverviewDialog"});
+  TapOnGetStartedAndWaitForScreenExit();
+
+  // Expect the screen to be marked as shown.
+  EXPECT_TRUE(ProfileManager::GetActiveUserProfile()->GetPrefs()->GetBoolean(
+      prefs::kOobeMarketingOptInScreenFinished));
+}
+
+IN_PROC_BROWSER_TEST_F(MarketingOptInScreenTest, OptInFlow) {
+  ShowMarketingOptInScreen();
+  OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
+  // U.S. is the default region for the base tests.
+  ExpectOptedIn();
+  TapOnGetStartedAndWaitForScreenExit();
+
+  // Expect the user preference to have been stored as opted-in (true).
+  ExpectRecordedUserPrefRegardingChoice(true);
+}
+
+IN_PROC_BROWSER_TEST_F(MarketingOptInScreenTest, OptOutFlow) {
+  ShowMarketingOptInScreen();
+  OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
+  // U.S. is the default region for the base tests.
+  ExpectOptedIn();
+  OptOut();
+  TapOnGetStartedAndWaitForScreenExit();
+
+  // Expect the user preference to have been stored as opted-out (false).
+  ExpectRecordedUserPrefRegardingChoice(false);
+}
+
+// Tests that the option to sign up for emails isn't shown when the user
+// already made its choice.
+IN_PROC_BROWSER_TEST_F(MarketingOptInScreenTest, HideOptionWhenChoiceKnown) {
+  PerformLogin();
+  OobeScreenExitWaiter(GetFirstSigninScreen()).Wait();
+
+  // Mark the screen as shown before and the user's choice as 'not opted in'.
+  ProfileManager::GetPrimaryUserProfile()->GetPrefs()->SetBoolean(
+      prefs::kOobeMarketingOptInScreenFinished, true);
+  ProfileManager::GetPrimaryUserProfile()->GetPrefs()->SetBoolean(
+      prefs::kOobeMarketingOptInChoice, false);
+
+  LoginDisplayHost::default_host()->StartWizard(
+      MarketingOptInScreenView::kScreenId);
+
+  ExpectNoOptInOption();
+  TapOnGetStartedAndWaitForScreenExit();
+}
+
+// Tests that the option to sign up is shown if the screen was shown before
+// but the user did not have an option to sign up for emails. (No user
+// preference stored)
+IN_PROC_BROWSER_TEST_F(MarketingOptInScreenTest,
+                       ShowOptionWhenNoChoiceOnRecord) {
+  PerformLogin();
+  OobeScreenExitWaiter(GetFirstSigninScreen()).Wait();
+
+  ProfileManager::GetPrimaryUserProfile()->GetPrefs()->SetBoolean(
+      prefs::kOobeMarketingOptInScreenFinished, true);
+
+  LoginDisplayHost::default_host()->StartWizard(
+      MarketingOptInScreenView::kScreenId);
+
+  ExpectOptInOptionAvailable();
+  TapOnGetStartedAndWaitForScreenExit();
+
+  // Expect the user preference to have been stored as opted-in (true).
+  ExpectRecordedUserPrefRegardingChoice(true);
 }
 
 // Tests that the user can enable shelf navigation buttons in tablet mode from
@@ -375,7 +494,7 @@
 
   void SetUpLocalStateRegion() {
     RegionToCodeMap param = GetParam();
-    g_browser_process->local_state()->SetString(prefs::kSigninScreenTimezone,
+    g_browser_process->local_state()->SetString(::prefs::kSigninScreenTimezone,
                                                 param.region);
   }
 };
@@ -397,6 +516,7 @@
   ShowMarketingOptInScreen();
   OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
 
+  ExpectLegalFooterVisibility(param.requires_legal_footer);
   if (param.is_default_opt_in) {
     ExpectOptedIn();
   } else {
diff --git a/chrome/browser/chromeos/login/startup_utils.cc b/chrome/browser/chromeos/login/startup_utils.cc
index e7cc3ebc..12afef5 100644
--- a/chrome/browser/chromeos/login/startup_utils.cc
+++ b/chrome/browser/chromeos/login/startup_utils.cc
@@ -17,10 +17,12 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
+#include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/web_resource/web_resource_pref_names.h"
@@ -92,15 +94,25 @@
 void StartupUtils::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(prefs::kOobeComplete, false);
   registry->RegisterStringPref(prefs::kOobeScreenPending, "");
-  registry->RegisterIntegerPref(prefs::kDeviceRegistered, -1);
-  registry->RegisterBooleanPref(prefs::kEnrollmentRecoveryRequired, false);
-  registry->RegisterStringPref(prefs::kInitialLocale, "en-US");
+  registry->RegisterIntegerPref(::prefs::kDeviceRegistered, -1);
+  registry->RegisterBooleanPref(::prefs::kEnrollmentRecoveryRequired, false);
+  registry->RegisterStringPref(::prefs::kInitialLocale, "en-US");
   registry->RegisterBooleanPref(kDisableHIDDetectionScreenForTests, false);
 }
 
 // static
+void StartupUtils::RegisterOobeProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(
+      prefs::kOobeMarketingOptInScreenFinished, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kOobeMarketingOptInChoice, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
+}
+
+// static
 bool StartupUtils::IsEulaAccepted() {
-  return g_browser_process->local_state()->GetBoolean(prefs::kEulaAccepted);
+  return g_browser_process->local_state()->GetBoolean(::prefs::kEulaAccepted);
 }
 
 // static
@@ -110,7 +122,7 @@
 
 // static
 void StartupUtils::MarkEulaAccepted() {
-  SaveBoolPreferenceForced(prefs::kEulaAccepted, true);
+  SaveBoolPreferenceForced(::prefs::kEulaAccepted, true);
 }
 
 // static
@@ -122,7 +134,7 @@
   SaveBoolPreferenceForced(prefs::kOobeComplete, true);
 
   // Successful enrollment implies that recovery is not required.
-  SaveBoolPreferenceForced(prefs::kEnrollmentRecoveryRequired, false);
+  SaveBoolPreferenceForced(::prefs::kEnrollmentRecoveryRequired, false);
 }
 
 // static
@@ -142,7 +154,7 @@
 // static
 bool StartupUtils::IsDeviceRegistered() {
   int value =
-      g_browser_process->local_state()->GetInteger(prefs::kDeviceRegistered);
+      g_browser_process->local_state()->GetInteger(::prefs::kDeviceRegistered);
   if (value > 0) {
     // Recreate flag file in case it was lost.
     base::ThreadPool::PostTask(
@@ -157,14 +169,15 @@
     base::ThreadRestrictions::ScopedAllowIO allow_io;
     const base::FilePath oobe_complete_flag_path = GetOobeCompleteFlagPath();
     bool file_exists = base::PathExists(oobe_complete_flag_path);
-    SaveIntegerPreferenceForced(prefs::kDeviceRegistered, file_exists ? 1 : 0);
+    SaveIntegerPreferenceForced(::prefs::kDeviceRegistered,
+                                file_exists ? 1 : 0);
     return file_exists;
   }
 }
 
 // static
 void StartupUtils::MarkDeviceRegistered(base::OnceClosure done_callback) {
-  SaveIntegerPreferenceForced(prefs::kDeviceRegistered, 1);
+  SaveIntegerPreferenceForced(::prefs::kDeviceRegistered, 1);
   if (done_callback.is_null()) {
     base::ThreadPool::PostTask(
         FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
@@ -178,7 +191,7 @@
 
 // static
 void StartupUtils::MarkEnrollmentRecoveryRequired() {
-  SaveBoolPreferenceForced(prefs::kEnrollmentRecoveryRequired, true);
+  SaveBoolPreferenceForced(::prefs::kEnrollmentRecoveryRequired, true);
 }
 
 // static
@@ -195,7 +208,7 @@
 // static
 std::string StartupUtils::GetInitialLocale() {
   std::string locale =
-      g_browser_process->local_state()->GetString(prefs::kInitialLocale);
+      g_browser_process->local_state()->GetString(::prefs::kInitialLocale);
   if (!l10n_util::IsValidLocaleSyntax(locale))
     locale = "en-US";
   return locale;
@@ -204,7 +217,7 @@
 // static
 void StartupUtils::SetInitialLocale(const std::string& locale) {
   if (l10n_util::IsValidLocaleSyntax(locale))
-    SaveStringPreferenceForced(prefs::kInitialLocale, locale);
+    SaveStringPreferenceForced(::prefs::kInitialLocale, locale);
   else
     NOTREACHED();
 }
diff --git a/chrome/browser/chromeos/login/startup_utils.h b/chrome/browser/chromeos/login/startup_utils.h
index 426da521..6759319 100644
--- a/chrome/browser/chromeos/login/startup_utils.h
+++ b/chrome/browser/chromeos/login/startup_utils.h
@@ -64,8 +64,11 @@
   // Sets initial locale in local settings.
   static void SetInitialLocale(const std::string& locale);
 
-  // Registers OOBE preferences.
+  // Registers OOBE local state preferences .
   static void RegisterPrefs(PrefRegistrySimple* registry);
+
+  // Registers OOBE preferences that are associated with a profile.
+  static void RegisterOobeProfilePrefs(PrefRegistrySimple* registry);
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/device_state_mixin.cc b/chrome/browser/chromeos/login/test/device_state_mixin.cc
index 210da19..2bd699d2 100644
--- a/chrome/browser/chromeos/login/test/device_state_mixin.cc
+++ b/chrome/browser/chromeos/login/test/device_state_mixin.cc
@@ -13,6 +13,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/path_service.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
@@ -112,16 +113,16 @@
     case DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED:
     case DeviceStateMixin::State::OOBE_COMPLETED_DEMO_MODE:
       local_state->SetBoolean(prefs::kOobeComplete, true);
-      local_state->SetInteger(prefs::kDeviceRegistered, 1);
-      local_state->SetBoolean(prefs::kEnrollmentRecoveryRequired, false);
+      local_state->SetInteger(::prefs::kDeviceRegistered, 1);
+      local_state->SetBoolean(::prefs::kEnrollmentRecoveryRequired, false);
       break;
     case DeviceStateMixin::State::OOBE_COMPLETED_UNOWNED:
       local_state->SetBoolean(prefs::kOobeComplete, true);
-      local_state->SetInteger(prefs::kDeviceRegistered, 0);
-      local_state->SetBoolean(prefs::kEnrollmentRecoveryRequired, false);
+      local_state->SetInteger(::prefs::kDeviceRegistered, 0);
+      local_state->SetBoolean(::prefs::kEnrollmentRecoveryRequired, false);
       break;
     case DeviceStateMixin::State::BEFORE_OOBE:
-      local_state->SetInteger(prefs::kDeviceRegistered, 0);
+      local_state->SetInteger(::prefs::kDeviceRegistered, 0);
       break;
   }
 }
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 7c162da9..a4c7729a 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -46,6 +46,7 @@
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/hwid_checker.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
 #include "chrome/browser/chromeos/login/screens/active_directory_login_screen.h"
@@ -1717,8 +1718,8 @@
 
   UMA_HISTOGRAM_COUNTS_100(
       "HIDDetection.TimesDialogShownPerOOBECompleted",
-      GetLocalState()->GetInteger(prefs::kTimesHIDDialogShown));
-  GetLocalState()->ClearPref(prefs::kTimesHIDDialogShown);
+      GetLocalState()->GetInteger(::prefs::kTimesHIDDialogShown));
+  GetLocalState()->ClearPref(::prefs::kTimesHIDDialogShown);
   StartupUtils::MarkOobeCompleted();
   oobe_marked_completed_ = true;
 }
@@ -2078,7 +2079,7 @@
   bool shouldShowParentalControl =
       wizard_context_->sign_in_as_child && !profile->IsChild() &&
       !profile->GetProfilePolicyConnector()->IsManaged();
-  profile->GetPrefs()->SetBoolean(prefs::kHelpAppShouldShowParentalControl,
+  profile->GetPrefs()->SetBoolean(::prefs::kHelpAppShouldShowParentalControl,
                                   shouldShowParentalControl);
 }
 
diff --git a/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc
index d186521..e860fcc6 100644
--- a/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc
@@ -128,10 +128,10 @@
   // timestamp in microseconds. The policy blob contains a timestamp in
   // milliseconds. Convert from one to the other by multiplying by 1000.
   const int64_t invalidation_version = policy.policy_data().timestamp() * 1000;
-  syncer::Invalidation invalidation = syncer::Invalidation::Init(
+  invalidation::Invalidation invalidation = invalidation::Invalidation::Init(
       kPolicyInvalidationTopic, invalidation_version, "dummy payload");
 
-  syncer::TopicInvalidationMap invalidation_map;
+  invalidation::TopicInvalidationMap invalidation_map;
   invalidation_map.Insert(invalidation);
   invalidator->OnIncomingInvalidation(invalidation_map);
 
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
index c31f521..e061c319 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
@@ -72,7 +72,7 @@
 }  // namespace
 
 class AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver
-    : public syncer::InvalidationHandler {
+    : public invalidation::InvalidationHandler {
  public:
   explicit InvalidationServiceObserver(
       AffiliatedInvalidationServiceProviderImpl* parent,
@@ -83,10 +83,10 @@
   void CheckInvalidatorState();
   bool IsServiceConnected() const;
 
-  // public syncer::InvalidationHandler:
-  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  // public invalidation::InvalidationHandler:
+  void OnInvalidatorStateChange(invalidation::InvalidatorState state) override;
   void OnIncomingInvalidation(
-      const syncer::TopicInvalidationMap& invalidation_map) override;
+      const invalidation::TopicInvalidationMap& invalidation_map) override;
   std::string GetOwnerName() const override;
 
  private:
@@ -112,7 +112,7 @@
       is_observer_ready_(false) {
   invalidation_service_->RegisterInvalidationHandler(this);
   is_service_connected_ = invalidation_service->GetInvalidatorState() ==
-                          syncer::INVALIDATIONS_ENABLED;
+                          invalidation::INVALIDATIONS_ENABLED;
   is_observer_ready_ = true;
 }
 
@@ -140,13 +140,14 @@
   DCHECK(invalidation_service_);
   DCHECK(parent_);
 
-  syncer::InvalidatorState state = invalidation_service_->GetInvalidatorState();
-  bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
+  invalidation::InvalidatorState state =
+      invalidation_service_->GetInvalidatorState();
+  bool is_service_connected = (state == invalidation::INVALIDATIONS_ENABLED);
 
   if (is_service_connected_ == is_service_connected)
     return;
 
-  if (state == syncer::TRANSIENT_INVALIDATION_ERROR) {
+  if (state == invalidation::TRANSIENT_INVALIDATION_ERROR) {
     // Do not cause disconnect if the number of disconnections caused by
     // TRANSIENT_INVALIDATION_ERROR is more than the limit.
     if (!transient_error_disconnect_limit_)
@@ -162,7 +163,7 @@
 }
 
 void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
-    OnInvalidatorStateChange(syncer::InvalidatorState state) {
+    OnInvalidatorStateChange(invalidation::InvalidatorState state) {
   if (!is_observer_ready_)
     return;
 
@@ -174,13 +175,13 @@
     //   * state == TRANSIENT_INVALIDATION_ERROR, hopefully will be resolved by
     //     InvalidationService, if not InvalidationService should notify again
     //     with another more severe state.
-    bool should_notify = (state != syncer::INVALIDATIONS_ENABLED &&
-                          state != syncer::TRANSIENT_INVALIDATION_ERROR);
+    bool should_notify = (state != invalidation::INVALIDATIONS_ENABLED &&
+                          state != invalidation::TRANSIENT_INVALIDATION_ERROR);
 
     if (should_notify) {
       is_service_connected_ = false;
       parent_->OnInvalidationServiceDisconnected(invalidation_service_);
-    } else if (state == syncer::TRANSIENT_INVALIDATION_ERROR) {
+    } else if (state == invalidation::TRANSIENT_INVALIDATION_ERROR) {
       transient_error_retry_timer_.Stop();
       transient_error_retry_timer_.Start(
           FROM_HERE, kCheckInvalidatorStateDelay,
@@ -191,7 +192,7 @@
   } else {
     // If service is disconnected, ONLY notify parent in case:
     //   * state == INVALIDATIONS_ENABLED
-    bool should_notify = (state == syncer::INVALIDATIONS_ENABLED);
+    bool should_notify = (state == invalidation::INVALIDATIONS_ENABLED);
     if (should_notify) {
       is_service_connected_ = true;
       parent_->OnInvalidationServiceConnected(invalidation_service_);
@@ -201,7 +202,7 @@
 
 void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
     OnIncomingInvalidation(
-        const syncer::TopicInvalidationMap& invalidation_map) {}
+        const invalidation::TopicInvalidationMap& invalidation_map) {}
 
 std::string AffiliatedInvalidationServiceProviderImpl::
     InvalidationServiceObserver::GetOwnerName() const {
@@ -438,13 +439,13 @@
   auto device_invalidation_service =
       std::make_unique<invalidation::FCMInvalidationService>(
           device_identity_provider_.get(),
-          base::BindRepeating(&syncer::FCMNetworkHandler::Create,
+          base::BindRepeating(&invalidation::FCMNetworkHandler::Create,
                               g_browser_process->gcm_driver(),
                               device_instance_id_driver_.get()),
-          base::BindRepeating(&syncer::PerUserTopicSubscriptionManager::Create,
-                              device_identity_provider_.get(),
-                              g_browser_process->local_state(),
-                              base::RetainedRef(url_loader_factory)),
+          base::BindRepeating(
+              &invalidation::PerUserTopicSubscriptionManager::Create,
+              device_identity_provider_.get(), g_browser_process->local_state(),
+              base::RetainedRef(url_loader_factory)),
           device_instance_id_driver_.get(), g_browser_process->local_state(),
           policy::kPolicyFCMInvalidationSenderID);
   device_invalidation_service->Init();
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
index 2fb1a80..a1bf3720 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
@@ -57,7 +57,7 @@
   std::unique_ptr<invalidation::FakeInvalidationService> invalidation_service(
       new invalidation::FakeInvalidationService);
   invalidation_service->SetInvalidatorState(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
+      invalidation::TRANSIENT_INVALIDATION_ERROR);
   return invalidation_service;
 }
 
@@ -70,7 +70,7 @@
 
 void SendInvalidatorStateChangeNotification(
     invalidation::InvalidationService* service,
-    syncer::InvalidatorState state) {
+    invalidation::InvalidatorState state) {
   static_cast<invalidation::FCMInvalidationService*>(service)
       ->OnInvalidatorStateChange(state);
 }
@@ -78,8 +78,8 @@
 }  // namespace
 
 // A simple AffiliatedInvalidationServiceProvider::Consumer that registers a
-// syncer::FakeInvalidationHandler with the invalidation::InvalidationService
-// that is currently being made available.
+// invalidation::FakeInvalidationHandler with
+// the invalidation::InvalidationService that is currently being made available.
 class FakeConsumer : public AffiliatedInvalidationServiceProvider::Consumer {
  public:
   explicit FakeConsumer(AffiliatedInvalidationServiceProviderImpl* provider);
@@ -94,7 +94,7 @@
 
  private:
   AffiliatedInvalidationServiceProviderImpl* provider_;
-  syncer::FakeInvalidationHandler invalidation_handler_;
+  invalidation::FakeInvalidationHandler invalidation_handler_;
 
   int invalidation_service_set_count_ = 0;
   invalidation::InvalidationService* invalidation_service_ = nullptr;
@@ -287,7 +287,7 @@
   // that the consumer is informed about this.
   EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
   profile_invalidation_service_->SetInvalidatorState(
-      syncer::INVALIDATIONS_ENABLED);
+      invalidation::INVALIDATIONS_ENABLED);
   EXPECT_EQ(1, consumer_->GetAndClearInvalidationServiceSetCount());
   EXPECT_EQ(profile_invalidation_service_, consumer_->GetInvalidationService());
 
@@ -312,7 +312,7 @@
   // Indicate that the per-profile invalidation service has connected. Verify
   // that the consumer is not called back.
   profile_invalidation_service_->SetInvalidatorState(
-      syncer::INVALIDATIONS_ENABLED);
+      invalidation::INVALIDATIONS_ENABLED);
   EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
 
   // Verify that the device-global invalidation service still exists.
@@ -330,7 +330,7 @@
   // that the consumer is informed about this.
   EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
   SendInvalidatorStateChangeNotification(device_invalidation_service_,
-                                         syncer::INVALIDATIONS_ENABLED);
+                                         invalidation::INVALIDATIONS_ENABLED);
   EXPECT_EQ(1, consumer_->GetAndClearInvalidationServiceSetCount());
   EXPECT_EQ(device_invalidation_service_, consumer_->GetInvalidationService());
 }
@@ -343,7 +343,7 @@
   // that the consumer is informed about this.
   EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
   profile_invalidation_service_->SetInvalidatorState(
-      syncer::INVALIDATION_CREDENTIALS_REJECTED);
+      invalidation::INVALIDATION_CREDENTIALS_REJECTED);
   EXPECT_EQ(1, consumer_->GetAndClearInvalidationServiceSetCount());
   EXPECT_EQ(nullptr, consumer_->GetInvalidationService());
 
@@ -409,7 +409,8 @@
   // Verify that the consumer is informed about this.
   EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
   SendInvalidatorStateChangeNotification(
-      device_invalidation_service_, syncer::INVALIDATION_CREDENTIALS_REJECTED);
+      device_invalidation_service_,
+      invalidation::INVALIDATION_CREDENTIALS_REJECTED);
   EXPECT_EQ(1, consumer_->GetAndClearInvalidationServiceSetCount());
   EXPECT_EQ(nullptr, consumer_->GetInvalidationService());
 
@@ -562,7 +563,7 @@
   // Indicate that the second user's per-profile invalidation service has
   // connected. Verify that the consumer is not called back.
   second_profile_invalidation_service->SetInvalidatorState(
-      syncer::INVALIDATIONS_ENABLED);
+      invalidation::INVALIDATIONS_ENABLED);
   EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
 
   // Indicate that the first user's per-profile invalidation service has
@@ -571,7 +572,7 @@
   // user's.
   EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
   profile_invalidation_service_->SetInvalidatorState(
-      syncer::INVALIDATION_CREDENTIALS_REJECTED);
+      invalidation::INVALIDATION_CREDENTIALS_REJECTED);
   EXPECT_EQ(1, consumer_->GetAndClearInvalidationServiceSetCount());
   EXPECT_EQ(second_profile_invalidation_service,
             consumer_->GetInvalidationService());
@@ -661,7 +662,7 @@
   // Indicate that the second user's per-profile invalidation service has
   // connected. Verify that the consumer is not called back.
   second_profile_invalidation_service->SetInvalidatorState(
-      syncer::INVALIDATIONS_ENABLED);
+      invalidation::INVALIDATIONS_ENABLED);
   EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
 
   // Verify that the device-global invalidation service still does not exist.
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_initializer.cc b/chrome/browser/chromeos/policy/device_cloud_policy_initializer.cc
index d5eb53f..486a34d 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_initializer.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_initializer.cc
@@ -16,6 +16,7 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
@@ -176,7 +177,8 @@
 
   // If OOBE is done and we are not enrolled, make sure we only try interactive
   // enrollment.
-  const bool oobe_complete = local_state_->GetBoolean(prefs::kOobeComplete);
+  const bool oobe_complete =
+      local_state_->GetBoolean(chromeos::prefs::kOobeComplete);
   if (oobe_complete &&
       config.auth_mechanism == EnrollmentConfig::AUTH_MECHANISM_BEST_AVAILABLE)
     config.auth_mechanism = EnrollmentConfig::AUTH_MECHANISM_INTERACTIVE;
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
index da3bbbe..051ca26 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
 #include "chrome/browser/chromeos/policy/server_backed_device_state.h"
 #include "chrome/browser/prefs/browser_prefs.h"
@@ -163,7 +164,7 @@
 
   // If OOBE is complete, we may re-enroll to the domain configured in install
   // attributes. This is only enforced after detecting enrollment loss.
-  local_state_.SetBoolean(prefs::kOobeComplete, true);
+  local_state_.SetBoolean(chromeos::prefs::kOobeComplete, true);
   EnrollmentConfig config =
       device_cloud_policy_initializer_.GetPrescribedEnrollmentConfig();
   EXPECT_EQ(EnrollmentConfig::MODE_NONE, config.mode);
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
index ca924a7b..ff32301 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
@@ -141,9 +141,11 @@
 void DlpContentManager::OnScreenCaptureStarted(
     const std::string& label,
     std::vector<content::DesktopMediaID> screen_capture_ids,
+    const base::string16& application_title,
     content::MediaStreamUI::StateChangeCallback state_change_callback) {
   for (const content::DesktopMediaID& id : screen_capture_ids) {
-    ScreenCaptureInfo capture_info(label, id, state_change_callback);
+    ScreenCaptureInfo capture_info(label, id, application_title,
+                                   state_change_callback);
     DCHECK(!base::Contains(running_screen_captures_, capture_info));
     running_screen_captures_.push_back(capture_info);
   }
@@ -155,7 +157,13 @@
     const content::DesktopMediaID& media_id) {
   base::EraseIf(running_screen_captures_,
                 [=](const ScreenCaptureInfo& capture) -> bool {
-                  return capture.label == label && capture.media_id == media_id;
+                  const bool erased =
+                      capture.label == label && capture.media_id == media_id;
+                  if (erased && capture.showing_paused_notification)
+                    HideDlpScreenCapturePausedNotification(capture.label);
+                  if (erased && capture.showing_resumed_notification)
+                    HideDlpScreenCaptureResumedNotification(capture.label);
+                  return erased;
                 });
   MaybeUpdateScreenCaptureNotification();
 }
@@ -177,9 +185,11 @@
 DlpContentManager::ScreenCaptureInfo::ScreenCaptureInfo(
     const std::string& label,
     const content::DesktopMediaID& media_id,
+    const base::string16& application_title,
     content::MediaStreamUI::StateChangeCallback state_change_callback)
     : label(label),
       media_id(media_id),
+      application_title(application_title),
       state_change_callback(state_change_callback) {}
 DlpContentManager::ScreenCaptureInfo::ScreenCaptureInfo(
     const DlpContentManager::ScreenCaptureInfo& other) = default;
@@ -384,35 +394,33 @@
 }
 
 void DlpContentManager::MaybeUpdateScreenCaptureNotification() {
-  bool is_running = false;
-  bool is_paused = false;
   for (auto& capture : running_screen_captures_) {
-    is_running |= capture.is_running;
-    is_paused |= !capture.is_running;
-  }
-  // If a capture was paused and a "paused" notification was shown, but the
-  // capture is resumed/stopped - hide the "paused" notification.
-  if (showing_paused_notification_ && !is_paused) {
-    HideDlpScreenCapturePausedNotification();
-    showing_paused_notification_ = false;
-    // If a capture was paused and later resumed - show a "resumed" notification
-    // if not yet shown.
-    if (!showing_resumed_notification_ && is_running) {
-      ShowDlpScreenCaptureResumedNotification();
-      showing_resumed_notification_ = true;
+    // If the capture was paused and a "paused" notification was shown, but the
+    // capture is resumed - hide the "paused" notification.
+    if (capture.showing_paused_notification && capture.is_running) {
+      HideDlpScreenCapturePausedNotification(capture.label);
+      capture.showing_paused_notification = false;
+      // If the capture was paused and later resumed - show a "resumed"
+      // notification if not yet shown.
+      if (!capture.showing_resumed_notification) {
+        ShowDlpScreenCaptureResumedNotification(capture.label,
+                                                capture.application_title);
+        capture.showing_resumed_notification = true;
+      }
     }
-  }
-  // If a capture was resumed and "resumed" notification was shown, but the
-  // capture is not running anymore - hide the "resumed" notification.
-  if (showing_resumed_notification_ && !is_running) {
-    HideDlpScreenCaptureResumedNotification();
-    showing_resumed_notification_ = false;
-  }
-  // If a capture was paused, but no notification is yet shown - show "paused"
-  // notification.
-  if (!showing_paused_notification_ && is_paused) {
-    ShowDlpScreenCapturePausedNotification();
-    showing_paused_notification_ = true;
+    // If the capture was resumed and "resumed" notification was shown, but the
+    // capture is not running anymore - hide the "resumed" notification.
+    if (capture.showing_resumed_notification && !capture.is_running) {
+      HideDlpScreenCaptureResumedNotification(capture.label);
+      capture.showing_resumed_notification = false;
+    }
+    // If the capture was paused, but no notification is yet shown - show a
+    // "paused" notification.
+    if (!capture.showing_paused_notification && !capture.is_running) {
+      ShowDlpScreenCapturePausedNotification(capture.label,
+                                             capture.application_title);
+      capture.showing_paused_notification = true;
+    }
   }
 }
 
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
index 99200b38..396fa62 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.h
@@ -85,6 +85,7 @@
   void OnScreenCaptureStarted(
       const std::string& label,
       std::vector<content::DesktopMediaID> screen_capture_ids,
+      const base::string16& application_title,
       content::MediaStreamUI::StateChangeCallback state_change_callback);
 
   // Called when screen capture is stopped.
@@ -122,6 +123,7 @@
     ScreenCaptureInfo(
         const std::string& label,
         const content::DesktopMediaID& media_id,
+        const base::string16& application_title,
         content::MediaStreamUI::StateChangeCallback state_change_callback);
     ScreenCaptureInfo(const ScreenCaptureInfo& other);
     ScreenCaptureInfo& operator=(const ScreenCaptureInfo& other);
@@ -132,8 +134,11 @@
 
     std::string label;
     content::DesktopMediaID media_id;
+    base::string16 application_title;
     content::MediaStreamUI::StateChangeCallback state_change_callback;
     bool is_running = true;
+    bool showing_paused_notification = false;
+    bool showing_resumed_notification = false;
   };
 
   DlpContentManager();
@@ -206,11 +211,6 @@
 
   // List of the currently running screen captures.
   std::vector<ScreenCaptureInfo> running_screen_captures_;
-
-  // Indicates whether screen capture paused/resumed notification is currently
-  // shown.
-  bool showing_paused_notification_ = false;
-  bool showing_resumed_notification_ = false;
 };
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
index fccec76..0ee80a723 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "ash/public/cpp/ash_features.h"
 #include "base/json/json_writer.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h"
@@ -45,9 +46,9 @@
     DlpContentRestriction::kScreenShare);
 
 constexpr char kScreenCapturePausedNotificationId[] =
-    "screen_capture_dlp_paused";
+    "screen_capture_dlp_paused-label";
 constexpr char kScreenCaptureResumedNotificationId[] =
-    "screen_capture_dlp_resumed";
+    "screen_capture_dlp_resumed-label";
 
 constexpr char kAllowedUrl[] = "https://example.com";
 constexpr char kUrl1[] = "https://example1.com";
@@ -264,7 +265,8 @@
       browser()->window()->GetNativeWindow()->GetRootWindow();
   const auto media_id = content::DesktopMediaID::RegisterNativeWindow(
       content::DesktopMediaID::TYPE_SCREEN, root_window);
-  manager->OnScreenCaptureStarted("label", {media_id}, base::DoNothing());
+  manager->OnScreenCaptureStarted(
+      "label", {media_id}, base::UTF8ToUTF16("example.com"), base::DoNothing());
 
   EXPECT_FALSE(display_service_tester.GetNotification(
       kScreenCapturePausedNotificationId));
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_notification_helper.cc b/chrome/browser/chromeos/policy/dlp/dlp_notification_helper.cc
index a68c939..2ac0efc48 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_notification_helper.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_notification_helper.cc
@@ -21,10 +21,10 @@
 namespace {
 
 constexpr char kPrintBlockedNotificationId[] = "print_dlp_blocked";
-constexpr char kScreenCapturePausedNotificationId[] =
-    "screen_capture_dlp_paused";
-constexpr char kScreenCaptureResumedNotificationId[] =
-    "screen_capture_dlp_resumed";
+constexpr char kScreenCapturePausedNotificationPrefix[] =
+    "screen_capture_dlp_paused-";
+constexpr char kScreenCaptureResumedNotificationPrefix[] =
+    "screen_capture_dlp_resumed-";
 constexpr char kDlpPolicyNotifierId[] = "policy.dlp";
 
 void ShowDlpNotification(const std::string& id,
@@ -48,6 +48,14 @@
                 /*metadata=*/nullptr);
 }
 
+std::string GetCapturePausedNotificationId(const std::string& capture_id) {
+  return kScreenCapturePausedNotificationPrefix + capture_id;
+}
+
+std::string GetCaptureResumedNotificationId(const std::string& capture_id) {
+  return kScreenCaptureResumedNotificationPrefix + capture_id;
+}
+
 }  // namespace
 
 void ShowDlpPrintDisabledNotification() {
@@ -57,32 +65,36 @@
       l10n_util::GetStringUTF16(IDS_POLICY_DLP_PRINTING_BLOCKED_MESSAGE));
 }
 
-void HideDlpScreenCapturePausedNotification() {
+void HideDlpScreenCapturePausedNotification(const std::string& capture_id) {
   NotificationDisplayService::GetForProfile(
       ProfileManager::GetActiveUserProfile())
       ->Close(NotificationHandler::Type::TRANSIENT,
-              kScreenCapturePausedNotificationId);
+              GetCapturePausedNotificationId(capture_id));
 }
 
-void ShowDlpScreenCapturePausedNotification() {
+void ShowDlpScreenCapturePausedNotification(const std::string& capture_id,
+                                            const base::string16& app_title) {
   ShowDlpNotification(
-      kScreenCapturePausedNotificationId,
+      GetCapturePausedNotificationId(capture_id),
       l10n_util::GetStringUTF16(IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_TITLE),
-      l10n_util::GetStringUTF16(IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE));
+      l10n_util::GetStringFUTF16(IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE,
+                                 app_title));
 }
 
-void HideDlpScreenCaptureResumedNotification() {
+void HideDlpScreenCaptureResumedNotification(const std::string& capture_id) {
   NotificationDisplayService::GetForProfile(
       ProfileManager::GetActiveUserProfile())
       ->Close(NotificationHandler::Type::TRANSIENT,
-              kScreenCaptureResumedNotificationId);
+              GetCaptureResumedNotificationId(capture_id));
 }
 
-void ShowDlpScreenCaptureResumedNotification() {
+void ShowDlpScreenCaptureResumedNotification(const std::string& capture_id,
+                                             const base::string16& app_title) {
   ShowDlpNotification(
-      kScreenCaptureResumedNotificationId,
+      GetCaptureResumedNotificationId(capture_id),
       l10n_util::GetStringUTF16(IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_TITLE),
-      l10n_util::GetStringUTF16(IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE));
+      l10n_util::GetStringFUTF16(IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE,
+                                 app_title));
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_notification_helper.h b/chrome/browser/chromeos/policy/dlp/dlp_notification_helper.h
index 4e2a9154..525a7fdc 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_notification_helper.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_notification_helper.h
@@ -5,6 +5,10 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_NOTIFICATION_HELPER_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_NOTIFICATION_HELPER_H_
 
+#include <string>
+
+#include "base/strings/string16.h"
+
 namespace policy {
 
 // Shows a notification that printing is not allowed due to DLP rules.
@@ -13,10 +17,14 @@
 // Shows/hides a notification that screen capture was paused because
 // confidential content appeared in the captured area, or resumed when it left
 // the captured area.
-void HideDlpScreenCapturePausedNotification();
-void ShowDlpScreenCapturePausedNotification();
-void HideDlpScreenCaptureResumedNotification();
-void ShowDlpScreenCaptureResumedNotification();
+// Different captures are identified by |capture_id| and separated notifications
+// are shown for them. |app_title| is provided for a customized message.
+void HideDlpScreenCapturePausedNotification(const std::string& capture_id);
+void ShowDlpScreenCapturePausedNotification(const std::string& capture_id,
+                                            const base::string16& app_title);
+void HideDlpScreenCaptureResumedNotification(const std::string& capture_id);
+void ShowDlpScreenCaptureResumedNotification(const std::string& capture_id,
+                                             const base::string16& app_title);
 
 }  // namespace policy
 
diff --git a/chrome/browser/devtools/protocol/page_handler.cc b/chrome/browser/devtools/protocol/page_handler.cc
index fa22258b..5822cc32 100644
--- a/chrome/browser/devtools/protocol/page_handler.cc
+++ b/chrome/browser/devtools/protocol/page_handler.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/devtools/protocol/page_handler.h"
 
 #include "components/subresource_filter/content/browser/devtools_interaction_tracker.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "ui/gfx/image/image.h"
 
 PageHandler::PageHandler(content::WebContents* web_contents,
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 0ffebfa..59a4784f 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -4439,6 +4439,45 @@
   ASSERT_EQ(coordinator_waiter.num_download_created(), 1);
 }
 
+// Tests that download a canvas image will show the file chooser.
+IN_PROC_BROWSER_TEST_F(DownloadTest, SaveCanvasImage) {
+  EnableFileChooser(true);
+  embedded_test_server()->ServeFilesFromDirectory(GetTestDataDirectory());
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url =
+      embedded_test_server()->GetURL("/downloads/page_with_canvas_image.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Try to download a canvas image via a context menu.
+  std::unique_ptr<content::DownloadTestObserver> waiter(
+      new content::DownloadTestObserverTerminal(
+          DownloadManagerForBrowser(browser()), 1,
+          content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL));
+
+  // Right-click on the link and choose Save Image As. This will download the
+  // canvas image.
+  ContextMenuNotificationObserver context_menu_observer(
+      IDC_CONTENT_CONTEXT_SAVEIMAGEAS);
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  blink::WebMouseEvent mouse_event(
+      blink::WebInputEvent::Type::kMouseDown,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::GetStaticTimeStampForTests());
+  mouse_event.button = blink::WebMouseEvent::Button::kRight;
+  mouse_event.SetPositionInWidget(15, 15);
+  mouse_event.click_count = 1;
+  tab->GetMainFrame()->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+      mouse_event);
+  mouse_event.SetType(blink::WebInputEvent::Type::kMouseUp);
+  tab->GetMainFrame()->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
+      mouse_event);
+  waiter->WaitForFinished();
+  EXPECT_EQ(1u, waiter->NumDownloadsSeenInState(DownloadItem::COMPLETE));
+  CheckDownloadStates(1, DownloadItem::COMPLETE);
+  EXPECT_TRUE(DidShowFileChooser());
+}
+
 #if BUILDFLAG(FULL_SAFE_BROWSING)
 
 namespace {
diff --git a/chrome/browser/download/download_status_updater.cc b/chrome/browser/download/download_status_updater.cc
index d3773912..35cb496 100644
--- a/chrome/browser/download/download_status_updater.cc
+++ b/chrome/browser/download/download_status_updater.cc
@@ -12,6 +12,9 @@
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_keep_alive_types.h"
+#include "chrome/browser/profiles/scoped_profile_keep_alive.h"
 
 namespace {
 
@@ -127,6 +130,50 @@
     WasInProgressData::Clear(item);
   }
   UpdateAppIconDownloadProgress(item);
+  UpdateProfileKeepAlive(manager);
+}
+
+void DownloadStatusUpdater::OnManagerGoingDown(
+    content::DownloadManager* manager) {
+  Profile* profile = Profile::FromBrowserContext(manager->GetBrowserContext());
+  profile_keep_alives_.erase(profile);
+}
+
+void DownloadStatusUpdater::UpdateProfileKeepAlive(
+    content::DownloadManager* manager) {
+  if (!manager) {
+    // Can be null in tests.
+    return;
+  }
+
+  Profile* profile = Profile::FromBrowserContext(manager->GetBrowserContext());
+  DCHECK(profile);
+  if (profile->IsOffTheRecord())
+    return;
+
+  // Are we already holding a keepalive?
+  bool already_has_keep_alive =
+      (profile_keep_alives_.find(profile) != profile_keep_alives_.end());
+
+  // Do we still need to hold a keepalive?
+  content::DownloadManager::DownloadVector items;
+  manager->GetAllDownloads(&items);
+  auto items_it = base::ranges::find(items, download::DownloadItem::IN_PROGRESS,
+                                     &download::DownloadItem::GetState);
+  bool should_keep_alive = (items_it != items.end());
+
+  if (should_keep_alive == already_has_keep_alive) {
+    // The current state is already correct for this Profile. No changes needed.
+    return;
+  }
+
+  // The current state is incorrect. Acquire/release a keepalive.
+  if (should_keep_alive) {
+    profile_keep_alives_[profile] = std::make_unique<ScopedProfileKeepAlive>(
+        profile, ProfileKeepAliveOrigin::kDownloadInProgress);
+  } else {
+    profile_keep_alives_.erase(profile);
+  }
 }
 
 #if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/download/download_status_updater.h b/chrome/browser/download/download_status_updater.h
index 05016b1..a0f4448 100644
--- a/chrome/browser/download/download_status_updater.h
+++ b/chrome/browser/download/download_status_updater.h
@@ -13,6 +13,9 @@
 #include "components/download/public/common/download_item.h"
 #include "content/public/browser/download_manager.h"
 
+class Profile;
+class ScopedProfileKeepAlive;
+
 // Keeps track of download progress for the entire browser.
 class DownloadStatusUpdater
     : public download::AllDownloadItemNotifier::Observer {
@@ -34,6 +37,7 @@
   void AddManager(content::DownloadManager* manager);
 
   // AllDownloadItemNotifier::Observer
+  void OnManagerGoingDown(content::DownloadManager* manager) override;
   void OnDownloadCreated(content::DownloadManager* manager,
                          download::DownloadItem* item) override;
   void OnDownloadUpdated(content::DownloadManager* manager,
@@ -46,8 +50,18 @@
   // Virtual to be overridable for testing.
   virtual void UpdateAppIconDownloadProgress(download::DownloadItem* download);
 
+  // Updates the ScopedProfileKeepAlive for the profile tied to |manager|. If
+  // there are in-progress downloads, it will acquire a keepalive. Otherwise, it
+  // will release it.
+  //
+  // This prevents deleting the Profile* too early when there are still
+  // in-progress downloads, and the browser is not tearing down yet.
+  void UpdateProfileKeepAlive(content::DownloadManager* manager);
+
  private:
   std::vector<std::unique_ptr<download::AllDownloadItemNotifier>> notifiers_;
+  std::map<Profile*, std::unique_ptr<ScopedProfileKeepAlive>>
+      profile_keep_alives_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadStatusUpdater);
 };
diff --git a/chrome/browser/download/download_status_updater_unittest.cc b/chrome/browser/download/download_status_updater_unittest.cc
index 004496c..5f1a4ba 100644
--- a/chrome/browser/download/download_status_updater_unittest.cc
+++ b/chrome/browser/download/download_status_updater_unittest.cc
@@ -8,7 +8,15 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/browser_features.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_status_updater.h"
+#include "chrome/browser/profiles/profile_keep_alive_types.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
 #include "components/download/public/common/mock_download_item.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/mock_download_manager.h"
@@ -48,7 +56,9 @@
 
 class DownloadStatusUpdaterTest : public testing::Test {
  public:
-  DownloadStatusUpdaterTest() : updater_(new TestDownloadStatusUpdater()) {}
+  DownloadStatusUpdaterTest()
+      : updater_(new TestDownloadStatusUpdater()),
+        profile_manager_(TestingBrowserProcess::GetGlobal()) {}
 
   ~DownloadStatusUpdaterTest() override {
     for (size_t mgr_idx = 0; mgr_idx < managers_.size(); ++mgr_idx) {
@@ -66,6 +76,8 @@
     base::RunLoop().RunUntilIdle();  // Allow DownloadManager destruction.
   }
 
+  void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); }
+
  protected:
   // Attach some number of DownloadManagers to the updater.
   void SetupManagers(int manager_count) {
@@ -91,6 +103,10 @@
     EXPECT_CALL(*mgr, AddObserver(_))
         .WillOnce(WithArg<0>(Invoke(
             this, &DownloadStatusUpdaterTest::SetObserver)));
+    TestingProfile* profile = profile_manager_.CreateTestingProfile(
+        base::StringPrintf("Profile %d", i + 1));
+    testing_profiles_.push_back(profile);
+    EXPECT_CALL(*mgr, GetBrowserContext()).WillRepeatedly(Return(profile));
     updater_->AddManager(mgr);
   }
 
@@ -185,6 +201,10 @@
   // TODO(rdsmith): This can be removed when the DownloadManager
   // is no longer required to be deleted on the UI thread.
   content::BrowserTaskEnvironment task_environment_;
+
+  // To test ScopedProfileKeepAlive behavior.
+  TestingProfileManager profile_manager_;
+  std::vector<TestingProfile*> testing_profiles_;
 };
 
 // Test null updater.
@@ -342,3 +362,34 @@
   EXPECT_FLOAT_EQ((10+50+80)/(20.0f+60+90), progress);
   EXPECT_EQ(3, download_count);
 }
+
+// Test that it prevents Profile deletion.
+TEST_F(DownloadStatusUpdaterTest, HoldsKeepAlive) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kDestroyProfileOnBrowserClose);
+
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  ASSERT_NE(nullptr, profile_manager);
+
+  SetupManagers(2);
+  AddItems(0, 2, 1);
+  LinkManager(0);
+  AddItems(1, 2, 0);
+  LinkManager(1);
+
+  // Profile 1 has a download in progress.
+  Profile* profile1 = testing_profiles_[0];
+  SetItemValues(0, 0, 10, 20, true);
+  EXPECT_TRUE(profile_manager->HasKeepAliveForTesting(
+      profile1, ProfileKeepAliveOrigin::kDownloadInProgress));
+
+  // Profile 2 doesn't have a download in progress.
+  Profile* profile2 = testing_profiles_[1];
+  EXPECT_FALSE(profile_manager->HasKeepAliveForTesting(
+      profile2, ProfileKeepAliveOrigin::kDownloadInProgress));
+
+  // Complete Profile 1's download. It should release its keepalive.
+  CompleteItem(0, 0);
+  EXPECT_FALSE(profile_manager->HasKeepAliveForTesting(
+      profile1, ProfileKeepAliveOrigin::kDownloadInProgress));
+}
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 7ff55fa8..593974f4 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -782,7 +782,7 @@
     "//chrome/browser/web_applications",
     "//chrome/browser/web_applications/components",
     "//components/site_engagement/core/mojom:mojo_bindings",
-    "//components/webapps",
+    "//components/webapps/browser",
 
     # TODO(crbug.com/1065748): Remove this dependency:
     "//chrome/browser/web_applications/extensions",
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_api.cc b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
index 8a4c3424..143d6f7 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_api.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
@@ -65,7 +65,7 @@
   args->Remove(0, nullptr);
   // PLUGINS have been deprecated, so ignore requests for removing them.
   if (content_type_str == "plugins") {
-    *content_type = ContentSettingsType::PLUGINS;
+    *content_type = ContentSettingsType::DEPRECATED_PLUGINS;
     return true;
   }
   *content_type =
@@ -86,7 +86,7 @@
   std::unique_ptr<Clear::Params> params(Clear::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  if (content_type == ContentSettingsType::PLUGINS) {
+  if (content_type == ContentSettingsType::DEPRECATED_PLUGINS) {
     return RespondNow(
         Error(content_settings_api_constants::
                   kSettingPluginContentSettingsClearIsDisallowed));
@@ -126,7 +126,7 @@
   std::unique_ptr<Get::Params> params(Get::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  if (content_type == ContentSettingsType::PLUGINS) {
+  if (content_type == ContentSettingsType::DEPRECATED_PLUGINS) {
     return RespondNow(Error(content_settings_api_constants::
                                 kSettingPluginContentSettingsGetIsDisallowed));
   }
@@ -200,7 +200,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   // PLUGINS have been deprecated.
-  if (content_type == ContentSettingsType::PLUGINS) {
+  if (content_type == ContentSettingsType::DEPRECATED_PLUGINS) {
     return RespondNow(Error(content_settings_api_constants::
                                 kSettingPluginContentSettingsIsDisallowed));
   }
@@ -329,7 +329,7 @@
   ContentSettingsType content_type;
   EXTENSION_FUNCTION_VALIDATE(RemoveContentType(args_.get(), &content_type));
 
-  if (content_type != ContentSettingsType::PLUGINS) {
+  if (content_type != ContentSettingsType::DEPRECATED_PLUGINS) {
     return RespondNow(NoArguments());
   }
 
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
index c4952d12..9b923d9 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -42,8 +42,8 @@
 #include "chrome/common/extensions/extension_metrics.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "components/favicon/core/favicon_service.h"
-#include "components/webapps/installable/installable_manager.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/api/management/management_api.h"
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index b71cec8..2411272 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "ash/public/cpp/clipboard_history_controller.h"
+#include "ash/public/cpp/clipboard_image_model_factory.h"
 #include "ash/public/cpp/keyboard/keyboard_switches.h"
 #include "ash/public/cpp/keyboard/keyboard_types.h"
 #include "base/bind.h"
@@ -165,9 +166,20 @@
     content::BrowserContext* browser_context)
     : browser_context_(browser_context) {
   weak_this_ = weak_factory_.GetWeakPtr();
+
+  ash::ClipboardHistoryController* clipboard_history_controller =
+      ash::ClipboardHistoryController::Get();
+  if (clipboard_history_controller) {
+    clipboard_history_controller->AddObserver(this);
+  }
 }
 
-ChromeVirtualKeyboardDelegate::~ChromeVirtualKeyboardDelegate() {}
+ChromeVirtualKeyboardDelegate::~ChromeVirtualKeyboardDelegate() {
+  ash::ClipboardHistoryController* clipboard_history_controller =
+      ash::ClipboardHistoryController::Get();
+  if (clipboard_history_controller)
+    clipboard_history_controller->RemoveObserver(this);
+}
 
 void ChromeVirtualKeyboardDelegate::GetKeyboardConfig(
     OnKeyboardSettingsCallback on_settings_callback) {
@@ -341,6 +353,10 @@
   if (!clipboard_history_controller)
     return;
 
+  // Begin renderng all items in the clipboard history. Current items will
+  // render even if Deactivate() is called on the ClipboardImageModelFactory.
+  ash::ClipboardImageModelFactory::Get()->RenderCurrentPendingRequests();
+
   std::move(get_history_callback)
       .Run(clipboard_history_controller->GetHistoryValues(item_ids_filter));
 }
@@ -408,6 +424,77 @@
             chromeos::ScreenLocker::default_screen_locker()->locked()));
 }
 
+void ChromeVirtualKeyboardDelegate::OnClipboardHistoryItemListAddedOrRemoved() {
+  EventRouter* router = EventRouter::Get(browser_context_);
+  if (!router->HasEventListener(
+          keyboard_api::OnClipboardHistoryChanged::kEventName)) {
+    return;
+  }
+
+  ash::ClipboardHistoryController* clipboard_history_controller =
+      ash::ClipboardHistoryController::Get();
+  if (!clipboard_history_controller)
+    return;
+
+  auto item_ids = clipboard_history_controller->GetHistoryItemIds();
+
+  std::unique_ptr<base::ListValue> ids =
+      keyboard_api::OnClipboardHistoryChanged::Create(item_ids);
+
+  auto event = std::make_unique<extensions::Event>(
+      extensions::events::VIRTUAL_KEYBOARD_PRIVATE_ON_CLIPBOARD_HISTORY_CHANGED,
+      keyboard_api::OnClipboardHistoryChanged::kEventName, std::move(ids),
+      browser_context_);
+  router->BroadcastEvent(std::move(event));
+}
+
+void ChromeVirtualKeyboardDelegate::OnClipboardHistoryItemsUpdated(
+    const std::vector<base::UnguessableToken>& menu_item_ids) {
+  EventRouter* router = EventRouter::Get(browser_context_);
+  if (!router->HasEventListener(
+          keyboard_api::OnClipboardItemUpdated::kEventName)) {
+    return;
+  }
+
+  ash::ClipboardHistoryController* clipboard_history_controller =
+      ash::ClipboardHistoryController::Get();
+  if (!clipboard_history_controller)
+    return;
+
+  std::set<std::string> item_ids_filter;
+  for (const auto& id : menu_item_ids) {
+    item_ids_filter.insert(id.ToString());
+  }
+  // Make call to get the updated clipboard items.
+  base::Value updated_items =
+      clipboard_history_controller->GetHistoryValues(item_ids_filter);
+
+  // Broadcast an api event for each updated item.
+  for (auto& item : updated_items.GetList()) {
+    keyboard_api::ClipboardItem clipboard_item;
+    if (item.FindKey("imageData")) {
+      clipboard_item.image_data =
+          std::make_unique<std::string>(item.FindKey("imageData")->GetString());
+    }
+    if (item.FindKey("textData")) {
+      clipboard_item.text_data =
+          std::make_unique<std::string>(item.FindKey("textData")->GetString());
+    }
+    if (item.FindKey("idToken")) {
+      clipboard_item.id = item.FindKey("idToken")->GetString();
+    }
+
+    std::unique_ptr<base::ListValue> item_value =
+        keyboard_api::OnClipboardItemUpdated::Create(clipboard_item);
+
+    auto event = std::make_unique<extensions::Event>(
+        extensions::events::VIRTUAL_KEYBOARD_PRIVATE_ON_CLIPBOARD_ITEM_UPDATED,
+        keyboard_api::OnClipboardItemUpdated::kEventName, std::move(item_value),
+        browser_context_);
+    router->BroadcastEvent(std::move(event));
+  }
+}
+
 void ChromeVirtualKeyboardDelegate::OnHasInputDevices(
     OnKeyboardSettingsCallback on_settings_callback,
     bool has_audio_input_devices) {
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
index 84e32d0..5ab0e8f 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "ash/public/cpp/clipboard_history_controller.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -20,7 +21,9 @@
 
 namespace extensions {
 
-class ChromeVirtualKeyboardDelegate : public VirtualKeyboardDelegate {
+class ChromeVirtualKeyboardDelegate
+    : public VirtualKeyboardDelegate,
+      public ash::ClipboardHistoryController::Observer {
  public:
   explicit ChromeVirtualKeyboardDelegate(
       content::BrowserContext* browser_context);
@@ -64,6 +67,11 @@
       const api::virtual_keyboard::RestrictFeatures::Params& params) override;
 
  private:
+  // ash::ClipboardHistoryController::Observer:
+  void OnClipboardHistoryItemListAddedOrRemoved() override;
+  void OnClipboardHistoryItemsUpdated(
+      const std::vector<base::UnguessableToken>& menu_item_ids) override;
+
   void OnHasInputDevices(OnKeyboardSettingsCallback on_settings_callback,
                          bool has_audio_input_devices);
   void DispatchConfigChangeEvent(
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.cc b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
index f0f9b87..4d3fa7b3c 100644
--- a/chrome/browser/extensions/chrome_content_verifier_delegate.cc
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
@@ -283,16 +283,20 @@
   policy_extension_reinstaller_.reset();
 }
 
-// static
-bool ChromeContentVerifierDelegate::IsFromWebstore(const Extension& extension) {
+bool ChromeContentVerifierDelegate::IsFromWebstore(
+    const Extension& extension) const {
   // Use the InstallVerifier's |IsFromStore| method to avoid discrepancies
   // between which extensions are considered in-store.
   // See https://crbug.com/766806 for details.
-  if (!InstallVerifier::IsFromStore(extension)) {
+  if (!InstallVerifier::IsFromStore(extension, context_)) {
     // It's possible that the webstore update url was overridden for testing
     // so also consider extensions with the default (production) update url
-    // to be from the store as well.
-    if (ManifestURL::GetUpdateURL(&extension) !=
+    // to be from the store as well. Therefore update URL is compared with
+    // |GetDefaultWebstoreUpdateUrl|, not the |GetWebstoreUpdateUrl| used by
+    // |IsWebstoreUpdateUrl|.
+    ExtensionManagement* extension_management =
+        ExtensionManagementFactory::GetForBrowserContext(context_);
+    if (extension_management->GetEffectiveUpdateURL(extension) !=
         extension_urls::GetDefaultWebstoreUpdateUrl()) {
       return false;
     }
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.h b/chrome/browser/extensions/chrome_content_verifier_delegate.h
index d3b4865..8c99a698 100644
--- a/chrome/browser/extensions/chrome_content_verifier_delegate.h
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.h
@@ -85,7 +85,7 @@
  private:
   // Returns true iff |extension| is considered extension from Chrome Web Store
   // (and therefore signed hashes may be used for its content verification).
-  static bool IsFromWebstore(const Extension& extension);
+  bool IsFromWebstore(const Extension& extension) const;
 
   // Returns information needed for content verification of |extension|.
   VerifyInfo GetVerifyInfo(const Extension& extension) const;
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index a3676206e..aba96e5 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -1712,7 +1712,7 @@
                                          install_flags, install_parameter,
                                          ruleset_install_prefs);
   delayed_installs_.Remove(extension->id());
-  if (InstallVerifier::NeedsVerification(*extension))
+  if (InstallVerifier::NeedsVerification(*extension, GetBrowserContext()))
     InstallVerifier::Get(GetBrowserContext())->VerifyExtension(extension->id());
 
   FinishInstallation(extension);
diff --git a/chrome/browser/extensions/install_verifier.cc b/chrome/browser/extensions/install_verifier.cc
index 413cc3ae..8ee620b 100644
--- a/chrome/browser/extensions/install_verifier.cc
+++ b/chrome/browser/extensions/install_verifier.cc
@@ -181,14 +181,17 @@
 }
 
 // static
-bool InstallVerifier::NeedsVerification(const Extension& extension) {
-  return IsFromStore(extension) && CanUseExtensionApis(extension);
+bool InstallVerifier::NeedsVerification(const Extension& extension,
+                                        content::BrowserContext* context) {
+  return IsFromStore(extension, context) && CanUseExtensionApis(extension);
 }
 
 // static
-bool InstallVerifier::IsFromStore(const Extension& extension) {
+bool InstallVerifier::IsFromStore(const Extension& extension,
+                                  content::BrowserContext* context) {
   return extension.from_webstore() ||
-         ManifestURL::UpdatesFromGallery(&extension);
+         ExtensionManagementFactory::GetForBrowserContext(context)
+             ->UpdatesFromWebstore(extension);
 }
 
 void InstallVerifier::Init() {
@@ -332,7 +335,7 @@
   if (base::Contains(InstallSigner::GetForcedNotFromWebstore(),
                      extension->id())) {
     verified = false;
-  } else if (!IsFromStore(*extension)) {
+  } else if (!IsFromStore(*extension, context_)) {
     verified = false;
   } else if (!signature_ && (!bootstrap_check_complete_ ||
                              GetStatus() < VerifyStatus::ENFORCE_STRICT)) {
@@ -386,7 +389,7 @@
   for (ExtensionSet::const_iterator iter = extensions->begin();
        iter != extensions->end();
        ++iter) {
-    if (NeedsVerification(**iter))
+    if (NeedsVerification(**iter, context_))
       result.insert((*iter)->id());
   }
   return result;
diff --git a/chrome/browser/extensions/install_verifier.h b/chrome/browser/extensions/install_verifier.h
index 084a131..0ea0cd59 100644
--- a/chrome/browser/extensions/install_verifier.h
+++ b/chrome/browser/extensions/install_verifier.h
@@ -49,10 +49,12 @@
   static bool ShouldEnforce();
 
   // Returns whether |extension| is of a type that needs verification.
-  static bool NeedsVerification(const Extension& extension);
+  static bool NeedsVerification(const Extension& extension,
+                                content::BrowserContext* context);
 
   // Determines if an extension claims to be from the webstore.
-  static bool IsFromStore(const Extension& extension);
+  static bool IsFromStore(const Extension& extension,
+                          content::BrowserContext* context);
 
   // Initializes this object for use, including reading preferences and
   // validating the stored signature.
diff --git a/chrome/browser/extensions/install_verifier_unittest.cc b/chrome/browser/extensions/install_verifier_unittest.cc
index c6cd966..01d26a4 100644
--- a/chrome/browser/extensions/install_verifier_unittest.cc
+++ b/chrome/browser/extensions/install_verifier_unittest.cc
@@ -106,7 +106,7 @@
       AddExtensionAsPolicyInstalled(extension->id());
 
     EXPECT_EQ(test_case.expected_from_store_status == FROM_STORE,
-              InstallVerifier::IsFromStore(*extension));
+              InstallVerifier::IsFromStore(*extension, profile()));
     disable_reason::DisableReason disable_reason;
     base::string16 error;
     EXPECT_EQ(
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc
index 49a8914d..029f25b8e 100644
--- a/chrome/browser/extensions/updater/extension_updater.cc
+++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -371,14 +371,6 @@
   ExtensionUpdateCheckParams update_check_params;
 
   if (params.ids.empty()) {
-    // We have to mark high-priority extensions (such as policy-forced
-    // extensions or external component extensions) with foreground fetch
-    // priority; otherwise their installation may be throttled by bandwidth
-    // limits.
-    // See https://crbug.com/904600 and https://crbug.com/965686.
-    if (pending_extension_manager->HasHighPriorityPendingExtension())
-      params.fetch_priority = ManifestFetchData::FOREGROUND;
-
     // If no extension ids are specified, check for updates for all extensions.
     pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids);
 
@@ -393,12 +385,22 @@
       const bool is_corrupt_reinstall =
           pending_extension_manager->IsPolicyReinstallForCorruptionExpected(
               pending_id);
+      // We have to mark high-priority extensions (such as policy-forced
+      // extensions or external component extensions) with foreground fetch
+      // priority; otherwise their installation may be throttled by bandwidth
+      // limits.
+      // See https://crbug.com/904600 and https://crbug.com/965686.
+      const bool is_high_priority_extension_pending =
+          pending_extension_manager->HasHighPriorityPendingExtension();
       if (CanUseUpdateService(pending_id)) {
         update_check_params.update_info[pending_id].is_corrupt_reinstall =
             is_corrupt_reinstall;
       } else if (downloader_->AddPendingExtension(
                      pending_id, info->update_url(), info->install_source(),
-                     is_corrupt_reinstall, request_id, params.fetch_priority)) {
+                     is_corrupt_reinstall, request_id,
+                     is_high_priority_extension_pending
+                         ? ManifestFetchData::FOREGROUND
+                         : params.fetch_priority)) {
         request.in_progress_ids_.insert(pending_id);
         InstallStageTracker::Get(profile_)->ReportInstallationStage(
             pending_id, InstallStageTracker::Stage::DOWNLOADING);
diff --git a/chrome/browser/federated_learning/floc_id_provider_browsertest.cc b/chrome/browser/federated_learning/floc_id_provider_browsertest.cc
index 07aee604..297355b 100644
--- a/chrome/browser/federated_learning/floc_id_provider_browsertest.cc
+++ b/chrome/browser/federated_learning/floc_id_provider_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/federated_learning/floc_event_logger.h"
@@ -35,6 +36,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
+#include "content/public/test/browsing_data_remover_test_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -296,6 +298,17 @@
     run_loop.Run();
   }
 
+  void ClearCookiesBrowsingData() {
+    content::BrowsingDataRemover* remover =
+        content::BrowserContext::GetBrowsingDataRemover(browser()->profile());
+    content::BrowsingDataRemoverCompletionObserver observer(remover);
+    remover->RemoveAndReply(
+        base::Time(), base::Time::Max(),
+        content::BrowsingDataRemover::DATA_TYPE_COOKIES,
+        content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, &observer);
+    observer.BlockUntilCompletion();
+  }
+
   base::FilePath GetUniqueTemporaryPath() {
     CHECK(scoped_temp_dir_.IsValid() || scoped_temp_dir_.CreateUniqueTempDir());
     return scoped_temp_dir_.GetPath().AppendASCII(
@@ -507,7 +520,24 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FlocIdProviderWithCustomizedServicesBrowserTest,
-                       HistoryDeleteRecomputeFloc) {
+                       ClearCookiesInvalidateFloc) {
+  ConfigureReplacementHostAndPortForRemotePermissionService();
+
+  FinishOutstandingAsyncQueries();
+  EXPECT_TRUE(GetFlocId().IsValid());
+
+  EXPECT_EQ(1u, floc_event_logger_->NumberOfLogAttemptsQueued());
+
+  ClearCookiesBrowsingData();
+  FinishOutstandingAsyncQueries();
+
+  // The floc has been invalidated. Expect no additional event logging.
+  EXPECT_FALSE(GetFlocId().IsValid());
+  EXPECT_EQ(1u, floc_event_logger_->NumberOfLogAttemptsQueued());
+}
+
+IN_PROC_BROWSER_TEST_F(FlocIdProviderWithCustomizedServicesBrowserTest,
+                       HistoryDeleteInvalidateFloc) {
   ConfigureReplacementHostAndPortForRemotePermissionService();
 
   FinishOutstandingAsyncQueries();
diff --git a/chrome/browser/federated_learning/floc_id_provider_impl.cc b/chrome/browser/federated_learning/floc_id_provider_impl.cc
index 7f477305..d775b1e8 100644
--- a/chrome/browser/federated_learning/floc_id_provider_impl.cc
+++ b/chrome/browser/federated_learning/floc_id_provider_impl.cc
@@ -23,16 +23,24 @@
 // The placeholder sorting-lsh version when the sorting-lsh feature is disabled.
 constexpr uint32_t kSortingLshVersionPlaceholder = 0;
 
-// Checks whether we can keep using the previous floc. If so, write to
-// |next_compute_delay| the time period we should wait until the floc needs to
-// be recomputed.
-bool ShouldKeepUsingPreviousFloc(const FlocId& last_floc,
-                                 base::TimeDelta* next_compute_delay) {
+struct StartupComputeDecision {
+  bool invalidate_existing_floc = true;
+  // Will be base::nullopt if should recompute immediately.
+  base::Optional<base::TimeDelta> next_compute_delay;
+};
+
+// Determine whether we can keep using the previous floc and/or when should the
+// next floc computation occur.
+StartupComputeDecision GetStartupComputeDecision(
+    const FlocId& last_floc,
+    base::Time floc_accessible_since) {
   // The floc has never been computed. This could happen with a fresh profile,
   // or some early trigger conditions were never met (e.g. sorting-lsh file has
   // never been ready).
-  if (last_floc.compute_time().is_null())
-    return false;
+  if (last_floc.compute_time().is_null()) {
+    return StartupComputeDecision{.invalidate_existing_floc = true,
+                                  .next_compute_delay = base::nullopt};
+  }
 
   // The browser started with a kFlocIdFinchConfigVersion param different from
   // the param when floc was computed last time.
@@ -44,7 +52,8 @@
   // wouldn't arrive due to e.g. component updater issue.
   if (last_floc.finch_config_version() !=
       static_cast<uint32_t>(kFlocIdFinchConfigVersion.Get())) {
-    return false;
+    return StartupComputeDecision{.invalidate_existing_floc = true,
+                                  .next_compute_delay = base::nullopt};
   }
 
   base::TimeDelta presumed_next_compute_delay =
@@ -52,19 +61,33 @@
       base::Time::Now();
 
   // The last floc has expired.
-  if (presumed_next_compute_delay <= base::TimeDelta())
-    return false;
+  if (presumed_next_compute_delay <= base::TimeDelta()) {
+    return StartupComputeDecision{.invalidate_existing_floc = true,
+                                  .next_compute_delay = base::nullopt};
+  }
 
   // This could happen if the machine time has changed since the last
-  // computation. Return false in order to keep computing the floc at the
-  // anticipated schedule rather than potentially stop computing for a very long
-  // time.
-  if (presumed_next_compute_delay >= 2 * kFlocIdScheduledUpdateInterval.Get())
-    return false;
+  // computation. Recompute immediately to align with the expected schedule
+  // rather than potentially stop computing for a very long time.
+  if (presumed_next_compute_delay >= 2 * kFlocIdScheduledUpdateInterval.Get()) {
+    return StartupComputeDecision{.invalidate_existing_floc = true,
+                                  .next_compute_delay = base::nullopt};
+  }
 
-  *next_compute_delay = presumed_next_compute_delay;
+  // Normally "floc_accessible_since <= last_floc.history_begin_time()" is an
+  // invariant, because we monitor its update and reset the floc accordingly.
+  // But "Clear on exit" may cause a cookie deletion on shutdown (practically on
+  // startup) that will reset floc_accessible_since to base::Time::Now and
+  // break the invariant on startup.
+  if (floc_accessible_since > last_floc.history_begin_time()) {
+    return StartupComputeDecision{
+        .invalidate_existing_floc = true,
+        .next_compute_delay = presumed_next_compute_delay};
+  }
 
-  return true;
+  return StartupComputeDecision{
+      .invalidate_existing_floc = false,
+      .next_compute_delay = presumed_next_compute_delay};
 }
 
 }  // namespace
@@ -79,19 +102,23 @@
       history_service_(history_service),
       floc_event_logger_(std::move(floc_event_logger)),
       floc_id_(FlocId::ReadFromPrefs(prefs_)) {
+  privacy_sandbox_settings->AddObserver(this);
   history_service->AddObserver(this);
   g_browser_process->floc_sorting_lsh_clusters_service()->AddObserver(this);
 
-  // If the previous floc has expired, invalidate it. The next computation will
-  // be "immediate", i.e. will occur after we first observe that the SortingLSH
-  // file is loaded; otherwise, keep using the last floc (which may still have
-  // be invalid), and schedule a recompute event with the desired delay.
-  base::TimeDelta next_compute_delay;
-  if (ShouldKeepUsingPreviousFloc(floc_id_, &next_compute_delay)) {
-    ScheduleFlocComputation(next_compute_delay);
-  } else {
+  StartupComputeDecision decision = GetStartupComputeDecision(
+      floc_id_, privacy_sandbox_settings->FlocDataAccessibleSince());
+
+  // If the previous floc has expired, invalidate it; otherwise, keep using the
+  // previous floc though it may already be invalid.
+  if (decision.invalidate_existing_floc)
     floc_id_.InvalidateIdAndSaveToPrefs(prefs_);
-  }
+
+  // Schedule the next floc computation if a delay is needed; otherwise, the
+  // next computation will occur immediately, or as soon as the sorting-lsh file
+  // is loaded when the sorting-lsh feature is enabled.
+  if (decision.next_compute_delay.has_value())
+    ScheduleFlocComputation(decision.next_compute_delay.value());
 
   if (g_browser_process->floc_sorting_lsh_clusters_service()
           ->IsSortingLshClustersFileReady()) {
@@ -147,13 +174,35 @@
 }
 
 void FlocIdProviderImpl::Shutdown() {
-  if (history_service_)
-    history_service_->RemoveObserver(this);
-  history_service_ = nullptr;
-
+  privacy_sandbox_settings_->RemoveObserver(this);
+  history_service_->RemoveObserver(this);
   g_browser_process->floc_sorting_lsh_clusters_service()->RemoveObserver(this);
 }
 
+void FlocIdProviderImpl::OnFlocDataAccessibleSinceUpdated() {
+  // Set the |need_recompute_| flag so that we will recompute the floc
+  // immediately after the in-progress one finishes, so as to avoid potential
+  // data races.
+  if (floc_computation_in_progress_) {
+    need_recompute_ = true;
+    return;
+  }
+
+  // Note: we only invalidate the floc rather than recomputing, because we don't
+  // want the floc to change more frequently than the scheduled update rate.
+
+  // No-op if the floc is already invalid.
+  if (!floc_id_.IsValid())
+    return;
+
+  // Invalidate the floc if the new floc-accessible-since time is greater than
+  // the begin time of the history used to compute the current floc.
+  if (privacy_sandbox_settings_->FlocDataAccessibleSince() >
+      floc_id_.history_begin_time()) {
+    floc_id_.InvalidateIdAndSaveToPrefs(prefs_);
+  }
+}
+
 void FlocIdProviderImpl::OnURLsDeleted(
     history::HistoryService* history_service,
     const history::DeletionInfo& deletion_info) {
@@ -198,8 +247,8 @@
 
 void FlocIdProviderImpl::MaybeTriggerImmediateComputation() {
   // If the floc computation is neither in progress nor scheduled, it means we
-  // want to trigger an immediate computation as soon as the sorting-lsh file is
-  // loaded.
+  // want to trigger an immediate computation, or as soon as the sorting-lsh
+  // file is loaded when the sorting-lsh feature is enabled.
   if (floc_computation_in_progress_ || compute_floc_timer_.IsRunning())
     return;
 
@@ -254,8 +303,13 @@
 
 void FlocIdProviderImpl::GetRecentlyVisitedURLs(
     GetRecentlyVisitedURLsCallback callback) {
+  base::Time now = base::Time::Now();
+
   history::QueryOptions options;
-  options.SetRecentDayRange(kQueryHistoryWindowInDays);
+  options.begin_time =
+      std::max(privacy_sandbox_settings_->FlocDataAccessibleSince(),
+               now - base::TimeDelta::FromDays(kQueryHistoryWindowInDays));
+  options.end_time = now;
   options.duplicate_policy = history::QueryOptions::KEEP_ALL_DUPLICATES;
 
   history_service_->QueryHistory(base::string16(), options, std::move(callback),
diff --git a/chrome/browser/federated_learning/floc_id_provider_impl.h b/chrome/browser/federated_learning/floc_id_provider_impl.h
index bcc4fb6d..9d8b89c 100644
--- a/chrome/browser/federated_learning/floc_id_provider_impl.h
+++ b/chrome/browser/federated_learning/floc_id_provider_impl.h
@@ -9,12 +9,11 @@
 #include "base/task/cancelable_task_tracker.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/federated_learning/floc_id_provider.h"
+#include "chrome/browser/privacy_sandbox/privacy_sandbox_settings.h"
 #include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_service_observer.h"
 
-class PrivacySandboxSettings;
-
 namespace federated_learning {
 
 class FlocEventLogger;
@@ -48,9 +47,14 @@
 //
 // In the event of history deletion, the floc will be invalidated immediately if
 // the time range of the deletion overlaps with the time range used to compute
-// the existing floc.
+// the existing floc. In the event of cookie deletion, the floc will always be
+// invalidated. Note that we only invalidate the floc rather than recomputing,
+// because we don't want the floc to change more frequently than the scheduled
+// update rate (% rare cases such as when the finch version param has changed
+// indicating a new algorithm / experiment, a recompute will be needed).
 class FlocIdProviderImpl : public FlocIdProvider,
                            public FlocSortingLshClustersService::Observer,
+                           public PrivacySandboxSettings::Observer,
                            public history::HistoryServiceObserver {
  public:
   struct ComputeFlocResult {
@@ -101,8 +105,16 @@
   // KeyedService:
   void Shutdown() override;
 
+  // PrivacySandboxSettings::Observer
+
+  // When the floc-accessible-since time is updated (due to e.g. cookies
+  // deletion), we'll either invalidate or keep using the floc. This will
+  // depend on the updated time and the begin time of the history used to
+  // compute the current floc.
+  void OnFlocDataAccessibleSinceUpdated() override;
+
   // history::HistoryServiceObserver
-  //
+
   // On history deletion, we'll either invalidate or keep using the floc. This
   // will depend on the deletion type and the time range.
   void OnURLsDeleted(history::HistoryService* history_service,
diff --git a/chrome/browser/federated_learning/floc_id_provider_unittest.cc b/chrome/browser/federated_learning/floc_id_provider_unittest.cc
index 9d308d7d..a42d9a5 100644
--- a/chrome/browser/federated_learning/floc_id_provider_unittest.cc
+++ b/chrome/browser/federated_learning/floc_id_provider_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/history/core/browser/history_database_params.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/test/test_history_database.h"
+#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
@@ -183,6 +184,7 @@
 
   void SetUp() override {
     FlocId::RegisterPrefs(prefs_.registry());
+    privacy_sandbox::RegisterProfilePrefs(prefs_.registry());
 
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
 
@@ -235,6 +237,10 @@
     floc_id_provider_->CheckCanComputeFloc(std::move(callback));
   }
 
+  void OnFlocDataAccessibleSinceUpdated() {
+    floc_id_provider_->OnFlocDataAccessibleSinceUpdated();
+  }
+
   void OnURLsDeleted(history::HistoryService* history_service,
                      const history::DeletionInfo& deletion_info) {
     floc_id_provider_->OnURLsDeleted(history_service, deletion_info);
@@ -476,8 +482,7 @@
   EXPECT_TRUE(floc_computation_scheduled());
 
   const base::Time kTime = base::Time::Now() - base::TimeDelta::FromDays(6);
-  AddHistoryEntriesForDomains({"foo.com"},
-                              base::Time::Now() - base::TimeDelta::FromDays(6));
+  AddHistoryEntriesForDomains({"foo.com"}, kTime);
 
   // Advance the clock by 23 hours. Expect no more computation, as the id
   // refresh interval is 24 hours.
@@ -498,11 +503,90 @@
 }
 
 TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
-       HistoryDeleteAndScheduledUpdate) {
+       HistoryQueryBoundedByFlocAccessibleSince) {
+  const base::Time kStartTime = base::Time::Now();
   const base::Time kSevenDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(7);
+      kStartTime - base::TimeDelta::FromDays(7);
   const base::Time kSixDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(6);
+      kStartTime - base::TimeDelta::FromDays(6);
+
+  prefs_.SetTime(prefs::kPrivacySandboxFlocDataAccessibleSince,
+                 kSixDaysBeforeStart);
+
+  AddHistoryEntriesForDomains({"foo.com"}, kSevenDaysBeforeStart);
+  AddHistoryEntriesForDomains({"bar.com"}, kSixDaysBeforeStart);
+
+  // Initializing the floc provider should trigger an immediate computation.
+  InitializeFlocIdProvider();
+  EXPECT_TRUE(floc_computation_in_progress());
+  EXPECT_FALSE(floc_computation_scheduled());
+
+  // Finish any outstanding history queries.
+  task_environment_.RunUntilIdle();
+
+  // Expect that the 1st computation has completed.
+  EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
+  EXPECT_EQ(1u, floc_id_provider_->log_event_count());
+  EXPECT_FALSE(floc_computation_in_progress());
+  EXPECT_TRUE(floc_computation_scheduled());
+
+  // Expected that floc is calculated from only "bar.com".
+  EXPECT_EQ(FlocId(FlocId::SimHashHistory({"bar.com"}), kSixDaysBeforeStart,
+                   kSixDaysBeforeStart, 0),
+            floc_id());
+}
+
+TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
+       FlocAccessibleSinceViolationOnStartup) {
+  const base::Time kStartTime = base::Time::Now();
+  const base::Time kSevenDaysBeforeStart =
+      kStartTime - base::TimeDelta::FromDays(7);
+  const base::Time kSixDaysBeforeStart =
+      kStartTime - base::TimeDelta::FromDays(6);
+  const base::Time kTwelveHoursBeforeStart =
+      kStartTime - base::TimeDelta::FromHours(12);
+
+  FlocId floc_id_in_prefs_before_start =
+      FlocIdTester::Create(123, kSevenDaysBeforeStart, kSixDaysBeforeStart, 1,
+                           0, kTwelveHoursBeforeStart);
+  floc_id_in_prefs_before_start.SaveToPrefs(&prefs_);
+
+  prefs_.SetTime(prefs::kPrivacySandboxFlocDataAccessibleSince,
+                 kSixDaysBeforeStart);
+
+  AddHistoryEntriesForDomains({"foo.com"}, kSevenDaysBeforeStart);
+  AddHistoryEntriesForDomains({"bar.com"}, kSixDaysBeforeStart);
+
+  // Initializing the floc provider should invalidate the previous floc but
+  // should not trigger an immediate computation.
+  InitializeFlocIdProvider();
+  EXPECT_FALSE(floc_computation_in_progress());
+  EXPECT_TRUE(floc_computation_scheduled());
+
+  EXPECT_FALSE(floc_id().IsValid());
+  EXPECT_FALSE(FlocId::ReadFromPrefs(&prefs_).IsValid());
+
+  // Fast forward by 12 hours. This should trigger a scheduled update.
+  task_environment_.FastForwardBy(base::TimeDelta::FromHours(12));
+
+  // Expect a completed computation and an update to the local prefs.
+  EXPECT_EQ(1u, floc_id_provider_->compute_floc_completed_count());
+  EXPECT_EQ(1u, floc_id_provider_->log_event_count());
+  EXPECT_FALSE(floc_computation_in_progress());
+  EXPECT_TRUE(floc_computation_scheduled());
+
+  EXPECT_EQ(floc_id(), FlocId(FlocId::SimHashHistory({"bar.com"}),
+                              kSixDaysBeforeStart, kSixDaysBeforeStart, 0));
+  EXPECT_EQ(floc_id(), FlocId::ReadFromPrefs(&prefs_));
+}
+
+TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
+       HistoryDeleteAndScheduledUpdate) {
+  const base::Time kStartTime = base::Time::Now();
+  const base::Time kSevenDaysBeforeStart =
+      kStartTime - base::TimeDelta::FromDays(7);
+  const base::Time kSixDaysBeforeStart =
+      kStartTime - base::TimeDelta::FromDays(6);
 
   AddHistoryEntriesForDomains({"foo.com"}, kSevenDaysBeforeStart);
   AddHistoryEntriesForDomains({"bar.com"}, kSixDaysBeforeStart);
@@ -603,6 +687,38 @@
   task_environment_.RunUntilIdle();
 }
 
+TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
+       OnFlocDataAccessibleSinceUpdated_TimeRangeNotFullyCovered) {
+  InitializeFlocIdProvider();
+  task_environment_.RunUntilIdle();
+
+  const base::Time kTime1 = base::Time::FromTimeT(1);
+  const base::Time kTime2 = base::Time::FromTimeT(2);
+
+  set_floc_id(FlocId(123, kTime1, kTime2, 0));
+
+  prefs_.SetTime(prefs::kPrivacySandboxFlocDataAccessibleSince, kTime2);
+  OnFlocDataAccessibleSinceUpdated();
+
+  EXPECT_FALSE(floc_id().IsValid());
+}
+
+TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
+       OnFlocDataAccessibleSinceUpdated_TimeRangeFullyCovered) {
+  InitializeFlocIdProvider();
+  task_environment_.RunUntilIdle();
+
+  const base::Time kTime1 = base::Time::FromTimeT(1);
+  const base::Time kTime2 = base::Time::FromTimeT(2);
+
+  set_floc_id(FlocId(123, kTime1, kTime2, 0));
+
+  prefs_.SetTime(prefs::kPrivacySandboxFlocDataAccessibleSince, kTime1);
+  OnFlocDataAccessibleSinceUpdated();
+
+  EXPECT_TRUE(floc_id().IsValid());
+}
+
 TEST_F(FlocIdProviderSimpleFeatureParamUnitTest, HistoryDelete_AllHistory) {
   InitializeFlocIdProvider();
   task_environment_.RunUntilIdle();
@@ -840,12 +956,13 @@
 
 TEST_F(FlocIdProviderUnitTestSortingLshEnabled,
        HistoryDeleteDuringInProgressComputation) {
+  const base::Time kStartTime = base::Time::Now();
   const base::Time kSevenDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(7);
+      kStartTime - base::TimeDelta::FromDays(7);
   const base::Time kSixDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(6);
+      kStartTime - base::TimeDelta::FromDays(6);
   const base::Time kFiveDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(5);
+      kStartTime - base::TimeDelta::FromDays(5);
 
   AddHistoryEntriesForDomains({"foo.com"}, kSevenDaysBeforeStart);
   AddHistoryEntriesForDomains({"bar.com"}, kSixDaysBeforeStart);
@@ -1040,12 +1157,13 @@
 TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
        LastFlocUnexpired_NextScheduledUpdate) {
   // Setups before session start.
+  const base::Time kStartTime = base::Time::Now();
   const base::Time kFourDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(4);
+      kStartTime - base::TimeDelta::FromDays(4);
   const base::Time kThreeDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(3);
+      kStartTime - base::TimeDelta::FromDays(3);
   const base::Time kLastComputeTime =
-      base::Time::Now() - base::TimeDelta::FromHours(12);
+      kStartTime - base::TimeDelta::FromHours(12);
 
   FlocId floc_id_in_prefs_before_start =
       FlocIdTester::Create(123, kFourDaysBeforeStart, kThreeDaysBeforeStart, 1,
@@ -1086,12 +1204,13 @@
 TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
        LastFlocUnexpired_HistoryDelete) {
   // Setups before session start.
+  const base::Time kStartTime = base::Time::Now();
   const base::Time kFourDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(4);
+      kStartTime - base::TimeDelta::FromDays(4);
   const base::Time kThreeDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(3);
+      kStartTime - base::TimeDelta::FromDays(3);
   const base::Time kLastComputeTime =
-      base::Time::Now() - base::TimeDelta::FromHours(12);
+      kStartTime - base::TimeDelta::FromHours(12);
 
   FlocId floc_id_in_prefs_before_start =
       FlocIdTester::Create(123, kFourDaysBeforeStart, kThreeDaysBeforeStart, 1,
@@ -1128,14 +1247,15 @@
 TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
        LastFlocExpired_ImmediateCompute) {
   // Setups before session start.
+  const base::Time kStartTime = base::Time::Now();
   const base::Time kTwentyDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(20);
+      kStartTime - base::TimeDelta::FromDays(20);
   const base::Time kNineteenDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(19);
+      kStartTime - base::TimeDelta::FromDays(19);
   const base::Time kTwoDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(2);
+      kStartTime - base::TimeDelta::FromDays(2);
   const base::Time kLastComputeTime =
-      base::Time::Now() - base::TimeDelta::FromHours(25);
+      kStartTime - base::TimeDelta::FromHours(25);
 
   FlocId floc_id_in_prefs_before_start =
       FlocIdTester::Create(123, kTwentyDaysBeforeStart,
@@ -1177,14 +1297,14 @@
 TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
        NextComputeDelayTooBig_ImmediateCompute) {
   // Setups before session start.
+  const base::Time kStartTime = base::Time::Now();
   const base::Time kFourDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(4);
+      kStartTime - base::TimeDelta::FromDays(4);
   const base::Time kThreeDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(3);
+      kStartTime - base::TimeDelta::FromDays(3);
   const base::Time kTwoDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(2);
-  const base::Time kLastComputeTime =
-      base::Time::Now() + base::TimeDelta::FromDays(1);
+      kStartTime - base::TimeDelta::FromDays(2);
+  const base::Time kLastComputeTime = kStartTime + base::TimeDelta::FromDays(1);
 
   // Configure the last compute time to be 1 day after the start time, that
   // emulates the situation when the machine time has changed.
@@ -1227,14 +1347,15 @@
 TEST_F(FlocIdProviderSimpleFeatureParamUnitTest,
        LastFlocVersionMismatch_ImmediateCompute) {
   // Setups before session start.
+  const base::Time kStartTime = base::Time::Now();
   const base::Time kFourDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(4);
+      kStartTime - base::TimeDelta::FromDays(4);
   const base::Time kThreeDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(3);
+      kStartTime - base::TimeDelta::FromDays(3);
   const base::Time kTwoDaysBeforeStart =
-      base::Time::Now() - base::TimeDelta::FromDays(2);
+      kStartTime - base::TimeDelta::FromDays(2);
   const base::Time kLastComputeTime =
-      base::Time::Now() - base::TimeDelta::FromHours(12);
+      kStartTime - base::TimeDelta::FromHours(12);
 
   // Configure a floc with version finch_config_version 0, that is different
   // from the current version 1.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index faf4cfc..a5b82f04 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3363,6 +3363,11 @@
     "expiry_milestone": 92
   },
   {
+    "name": "mobile-pwa-install-use-bottom-sheet",
+    "owners": [ "finnur", "hartmanng", "peter" ],
+    "expiry_milestone": 94
+  },
+  {
     "name": "modern-tab-strip",
     "owners": [ "nazerke", "bling-flags@google.com" ],
     "expiry_milestone": 92
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 5a84604..b6ab4612 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1420,6 +1420,11 @@
     "Enables stronger identity consistency on mobile with different UI "
     "variations";
 
+const char kMobilePwaInstallUseBottomSheetName[] =
+    "Mobile PWA Installation bottom sheet";
+const char kMobilePwaInstallUseBottomSheetDescription[] =
+    "Enables use of a rich bottom sheet when offering mobile PWA installation.";
+
 const char kMouseSubframeNoImplicitCaptureName[] =
     "Disable mouse implicit capture for iframe";
 const char kMouseSubframeNoImplicitCaptureDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index f4ae4db..9c807ac 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -840,6 +840,9 @@
 extern const char kMobileIdentityConsistencyVarName[];
 extern const char kMobileIdentityConsistencyVarDescription[];
 
+extern const char kMobilePwaInstallUseBottomSheetName[];
+extern const char kMobilePwaInstallUseBottomSheetDescription[];
+
 extern const char kMouseSubframeNoImplicitCaptureName[];
 extern const char kMouseSubframeNoImplicitCaptureDescription[];
 
diff --git a/chrome/browser/installable/installable_manager_browsertest.cc b/chrome/browser/installable/installable_manager_browsertest.cc
index ec020f6..da85be5e 100644
--- a/chrome/browser/installable/installable_manager_browsertest.cc
+++ b/chrome/browser/installable/installable_manager_browsertest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 
 #include <tuple>
 
@@ -23,9 +23,9 @@
 #include "chrome/browser/web_applications/test/service_worker_registration_waiter.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/webapps/installable/installable_logging.h"
-#include "components/webapps/installable/installable_manager.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
index 2f5c2d9..cc4d031 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
@@ -51,12 +51,12 @@
   auto service = std::make_unique<FCMInvalidationService>(
       identity_provider,
       base::BindRepeating(
-          &syncer::FCMNetworkHandler::Create,
+          &FCMNetworkHandler::Create,
           gcm::GCMProfileServiceFactory::GetForProfile(profile)->driver(),
           instance_id::InstanceIDProfileServiceFactory::GetForProfile(profile)
               ->driver()),
       base::BindRepeating(
-          &syncer::PerUserTopicSubscriptionManager::Create, identity_provider,
+          &PerUserTopicSubscriptionManager::Create, identity_provider,
           profile->GetPrefs(),
           base::RetainedRef(
               content::BrowserContext::GetDefaultStoragePartition(profile)
diff --git a/chrome/browser/media/webrtc/desktop_capture_devices_util.cc b/chrome/browser/media/webrtc/desktop_capture_devices_util.cc
index 76fede32..9fa27d4a 100644
--- a/chrome/browser/media/webrtc/desktop_capture_devices_util.cc
+++ b/chrome/browser/media/webrtc/desktop_capture_devices_util.cc
@@ -194,5 +194,6 @@
 
   return MediaCaptureDevicesDispatcher::GetInstance()
       ->GetMediaStreamCaptureIndicator()
-      ->RegisterMediaStream(web_contents, *devices, std::move(notification_ui));
+      ->RegisterMediaStream(web_contents, *devices, std::move(notification_ui),
+                            application_title);
 }
diff --git a/chrome/browser/media/webrtc/media_stream_capture_indicator.cc b/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
index 0296c444..aa23936 100644
--- a/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
+++ b/chrome/browser/media/webrtc/media_stream_capture_indicator.cc
@@ -148,7 +148,8 @@
 
   std::unique_ptr<content::MediaStreamUI> RegisterMediaStream(
       const blink::MediaStreamDevices& devices,
-      std::unique_ptr<MediaStreamUI> ui);
+      std::unique_ptr<MediaStreamUI> ui,
+      const base::string16 application_title);
 
   // Increment ref-counts up based on the type of each device provided.
   void AddDevices(const blink::MediaStreamDevices& devices,
@@ -190,8 +191,12 @@
  public:
   UIDelegate(base::WeakPtr<WebContentsDeviceUsage> device_usage,
              const blink::MediaStreamDevices& devices,
-             std::unique_ptr<::MediaStreamUI> ui)
-      : device_usage_(device_usage), devices_(devices), ui_(std::move(ui)) {
+             std::unique_ptr<::MediaStreamUI> ui,
+             const base::string16 application_title)
+      : device_usage_(device_usage),
+        devices_(devices),
+        ui_(std::move(ui)),
+        application_title_(std::move(application_title)) {
     DCHECK(!devices_.empty());
   }
 
@@ -224,7 +229,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     policy::DlpContentManager::Get()->OnScreenCaptureStarted(
-        label, screen_capture_ids, state_change_callback);
+        label, screen_capture_ids, application_title_, state_change_callback);
 #endif
 
     // If a custom |ui_| is specified, notify it that the stream started and let
@@ -246,6 +251,7 @@
   base::WeakPtr<WebContentsDeviceUsage> device_usage_;
   const blink::MediaStreamDevices devices_;
   const std::unique_ptr<::MediaStreamUI> ui_;
+  const base::string16 application_title_;
   bool started_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(UIDelegate);
@@ -254,9 +260,11 @@
 std::unique_ptr<content::MediaStreamUI>
 MediaStreamCaptureIndicator::WebContentsDeviceUsage::RegisterMediaStream(
     const blink::MediaStreamDevices& devices,
-    std::unique_ptr<MediaStreamUI> ui) {
+    std::unique_ptr<MediaStreamUI> ui,
+    const base::string16 application_title) {
   return std::make_unique<UIDelegate>(weak_factory_.GetWeakPtr(), devices,
-                                      std::move(ui));
+                                      std::move(ui),
+                                      std::move(application_title));
 }
 
 void MediaStreamCaptureIndicator::WebContentsDeviceUsage::AddDevices(
@@ -358,13 +366,15 @@
 MediaStreamCaptureIndicator::RegisterMediaStream(
     content::WebContents* web_contents,
     const blink::MediaStreamDevices& devices,
-    std::unique_ptr<MediaStreamUI> ui) {
+    std::unique_ptr<MediaStreamUI> ui,
+    const base::string16 application_title) {
   DCHECK(web_contents);
   auto& usage = usage_map_[web_contents];
   if (!usage)
     usage = std::make_unique<WebContentsDeviceUsage>(this, web_contents);
 
-  return usage->RegisterMediaStream(devices, std::move(ui));
+  return usage->RegisterMediaStream(devices, std::move(ui),
+                                    std::move(application_title));
 }
 
 void MediaStreamCaptureIndicator::ExecuteCommand(int command_id,
diff --git a/chrome/browser/media/webrtc/media_stream_capture_indicator.h b/chrome/browser/media/webrtc/media_stream_capture_indicator.h
index f0db8eca..18dc1a8 100644
--- a/chrome/browser/media/webrtc/media_stream_capture_indicator.h
+++ b/chrome/browser/media/webrtc/media_stream_capture_indicator.h
@@ -77,7 +77,8 @@
   std::unique_ptr<content::MediaStreamUI> RegisterMediaStream(
       content::WebContents* web_contents,
       const blink::MediaStreamDevices& devices,
-      std::unique_ptr<MediaStreamUI> ui = nullptr);
+      std::unique_ptr<MediaStreamUI> ui = nullptr,
+      const base::string16 application_title = base::string16());
 
   // Overrides from StatusIconMenuModel::Delegate implementation.
   void ExecuteCommand(int command_id, int event_flags) override;
diff --git a/chrome/browser/metrics/extensions_metrics_provider.cc b/chrome/browser/metrics/extensions_metrics_provider.cc
index 110ce2db..5dec856 100644
--- a/chrome/browser/metrics/extensions_metrics_provider.cc
+++ b/chrome/browser/metrics/extensions_metrics_provider.cc
@@ -16,6 +16,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/install_verifier.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -30,7 +31,6 @@
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handlers/background_info.h"
-#include "extensions/common/manifest_url_handlers.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 
 using extensions::Extension;
@@ -84,9 +84,9 @@
 // webstore, we attempt to verify with |verifier| by checking if it has been
 // explicitly deemed invalid. If |verifier| is inactive or if the extension is
 // unknown to |verifier|, the local information is trusted.
-ExtensionState IsOffStoreExtension(
-    const extensions::Extension& extension,
-    const extensions::InstallVerifier& verifier) {
+ExtensionState IsOffStoreExtension(const extensions::Extension& extension,
+                                   const extensions::InstallVerifier& verifier,
+                                   content::BrowserContext* context) {
   if (!extension.is_extension() && !extension.is_legacy_packaged_app())
     return NO_EXTENSIONS;
 
@@ -97,7 +97,7 @@
   if (verifier.AllowedByEnterprisePolicy(extension.id()))
     return NO_EXTENSIONS;
 
-  if (!extensions::InstallVerifier::IsFromStore(extension))
+  if (!extensions::InstallVerifier::IsFromStore(extension, context))
     return OFF_STORE;
 
   // Local information about the extension implies it is from the store. We try
@@ -115,14 +115,15 @@
 // highest (as defined by the order of ExtensionState) value of each extension
 // in |extensions|.
 ExtensionState CheckForOffStore(const extensions::ExtensionSet& extensions,
-                                const extensions::InstallVerifier& verifier) {
+                                const extensions::InstallVerifier& verifier,
+                                content::BrowserContext* context) {
   ExtensionState state = NO_EXTENSIONS;
   for (extensions::ExtensionSet::const_iterator it = extensions.begin();
        it != extensions.end() && state < OFF_STORE;
        ++it) {
     // Combine the state of each extension, always favoring the higher state as
     // defined by the order of ExtensionState.
-    state = std::max(state, IsOffStoreExtension(**it, verifier));
+    state = std::max(state, IsOffStoreExtension(**it, verifier, context));
   }
   return state;
 }
@@ -304,7 +305,8 @@
 metrics::ExtensionInstallProto ConstructInstallProto(
     const extensions::Extension& extension,
     extensions::ExtensionPrefs* prefs,
-    base::Time last_sample_time) {
+    base::Time last_sample_time,
+    extensions::ExtensionManagement* extension_management) {
   ExtensionInstallProto install;
   install.set_type(GetType(extension.manifest()->type()));
   install.set_install_location(GetInstallLocation(extension.location()));
@@ -315,7 +317,7 @@
   install.set_has_incognito_access(prefs->IsIncognitoEnabled(extension.id()));
   install.set_is_from_store(extension.from_webstore());
   install.set_updates_from_store(
-      extensions::ManifestURL::UpdatesFromGallery(&extension));
+      extension_management->UpdatesFromWebstore(extension));
   install.set_is_from_bookmark(extension.from_bookmark());
   install.set_is_converted_from_user_script(
       extension.converted_from_user_script());
@@ -343,9 +345,11 @@
           ->GenerateInstalledExtensionsSet();
   std::vector<ExtensionInstallProto> installs;
   installs.reserve(extensions->size());
+  extensions::ExtensionManagement* extension_management =
+      extensions::ExtensionManagementFactory::GetForBrowserContext(profile);
   for (const auto& extension : *extensions) {
-    installs.push_back(
-        ConstructInstallProto(*extension, prefs, last_sample_time));
+    installs.push_back(ConstructInstallProto(
+        *extension, prefs, last_sample_time, extension_management));
   }
 
   return installs;
@@ -401,8 +405,12 @@
 ExtensionsMetricsProvider::ConstructInstallProtoForTesting(
     const extensions::Extension& extension,
     extensions::ExtensionPrefs* prefs,
-    base::Time last_sample_time) {
-  return ConstructInstallProto(extension, prefs, last_sample_time);
+    base::Time last_sample_time,
+    Profile* profile) {
+  extensions::ExtensionManagement* extension_management =
+      extensions::ExtensionManagementFactory::GetForBrowserContext(profile);
+  return ConstructInstallProto(extension, prefs, last_sample_time,
+                               extension_management);
 }
 
 // static
@@ -435,7 +443,8 @@
 
     // Combine the state from each profile, always favoring the higher state as
     // defined by the order of ExtensionState.
-    state = std::max(state, CheckForOffStore(*extensions.get(), *verifier));
+    state = std::max(
+        state, CheckForOffStore(*extensions.get(), *verifier, profiles[i]));
   }
 
   system_profile->set_offstore_extensions_state(ExtensionStateAsProto(state));
diff --git a/chrome/browser/metrics/extensions_metrics_provider.h b/chrome/browser/metrics/extensions_metrics_provider.h
index aafc299b..206b9df 100644
--- a/chrome/browser/metrics/extensions_metrics_provider.h
+++ b/chrome/browser/metrics/extensions_metrics_provider.h
@@ -50,7 +50,8 @@
   static metrics::ExtensionInstallProto ConstructInstallProtoForTesting(
       const extensions::Extension& extension,
       extensions::ExtensionPrefs* prefs,
-      base::Time last_sample_time);
+      base::Time last_sample_time,
+      Profile* profile);
   static std::vector<metrics::ExtensionInstallProto>
   GetInstallsForProfileForTesting(Profile* profile,
                                   base::Time last_sample_time);
diff --git a/chrome/browser/metrics/extensions_metrics_provider_unittest.cc b/chrome/browser/metrics/extensions_metrics_provider_unittest.cc
index 03045041..ac99015 100644
--- a/chrome/browser/metrics/extensions_metrics_provider_unittest.cc
+++ b/chrome/browser/metrics/extensions_metrics_provider_unittest.cc
@@ -158,7 +158,7 @@
 
   ExtensionInstallProto ConstructProto(const Extension& extension) {
     return ExtensionsMetricsProvider::ConstructInstallProtoForTesting(
-        extension, prefs_, last_sample_time_);
+        extension, prefs_, last_sample_time_, profile());
   }
   std::vector<ExtensionInstallProto> GetInstallsForProfile() {
     return ExtensionsMetricsProvider::GetInstallsForProfileForTesting(
diff --git a/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc b/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
index ceb7e2b..3beca2e 100644
--- a/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
+++ b/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
@@ -70,13 +70,12 @@
           "FailureReason",
           http_status.GetResultCodeForMetrics());
     }
-  } else {
-    ss << " Missing URL loader.";
   }
+
   if (success) {
     NS_LOG(VERBOSE) << ss.str();
   } else {
-    NS_LOG(WARNING) << ss.str();
+    NS_LOG(ERROR) << ss.str();
   }
 }
 
@@ -124,7 +123,12 @@
         ReceiveMessagesExpressRequest& request,
     const std::string& oauth_token) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::UmaHistogramBoolean(
+      "Nearby.Connections.InstantMessaging.ReceiveExpress."
+      "OAuthTokenFetchResult",
+      !oauth_token.empty());
   if (oauth_token.empty()) {
+    NS_LOG(ERROR) << __func__ << ": Failed to fetch OAuth token.";
     std::move(success_callback_).Run(false);
     return;
   }
@@ -164,9 +168,10 @@
 
 void ReceiveMessagesExpress::OnComplete(bool success) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  LogReceiveResult(success, url_loader_.get());
-  if (!success_callback_.is_null())
+  if (!success_callback_.is_null()) {
+    LogReceiveResult(success, url_loader_.get());
     std::move(success_callback_).Run(success);
+  }
 
   url_loader_.reset();
   stream_parser_.reset();
@@ -178,6 +183,7 @@
 
 void ReceiveMessagesExpress::OnFastPathReady() {
   if (!success_callback_.is_null()) {
+    LogReceiveResult(/*success=*/true, /*loader=*/nullptr);
     std::move(success_callback_).Run(true);
   }
 }
diff --git a/chrome/browser/nearby_sharing/instantmessaging/send_message_express.cc b/chrome/browser/nearby_sharing/instantmessaging/send_message_express.cc
index abaa3518..ce5656c4 100644
--- a/chrome/browser/nearby_sharing/instantmessaging/send_message_express.cc
+++ b/chrome/browser/nearby_sharing/instantmessaging/send_message_express.cc
@@ -63,7 +63,7 @@
   if (success) {
     NS_LOG(VERBOSE) << ss.str();
   } else {
-    NS_LOG(WARNING) << ss.str();
+    NS_LOG(ERROR) << ss.str();
   }
   base::UmaHistogramBoolean(
       "Nearby.Connections.InstantMessaging.SendExpress.Result", success);
@@ -100,7 +100,11 @@
         SendMessageExpressRequest& request,
     SuccessCallback callback,
     const std::string& oauth_token) {
+  base::UmaHistogramBoolean(
+      "Nearby.Connections.InstantMessaging.SendExpress.OAuthTokenFetchResult",
+      !oauth_token.empty());
   if (oauth_token.empty()) {
+    NS_LOG(ERROR) << __func__ << ": Failed to fetch OAuth token.";
     std::move(callback).Run(false);
     return;
   }
diff --git a/chrome/browser/nearby_sharing/nearby_share_delegate_impl.cc b/chrome/browser/nearby_sharing/nearby_share_delegate_impl.cc
index de835fb..bf9c9e1 100644
--- a/chrome/browser/nearby_sharing/nearby_share_delegate_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_share_delegate_impl.cc
@@ -137,6 +137,10 @@
   }
 }
 
+void NearbyShareDelegateImpl::OnHighVisibilityChangeRequested() {
+  is_enable_high_visibility_request_active_ = true;
+}
+
 void NearbyShareDelegateImpl::OnHighVisibilityChanged(bool high_visibility_on) {
   is_enable_high_visibility_request_active_ = false;
 
diff --git a/chrome/browser/nearby_sharing/nearby_share_delegate_impl.h b/chrome/browser/nearby_sharing/nearby_share_delegate_impl.h
index 27fe748..47cb780 100644
--- a/chrome/browser/nearby_sharing/nearby_share_delegate_impl.h
+++ b/chrome/browser/nearby_sharing/nearby_share_delegate_impl.h
@@ -76,6 +76,7 @@
       const std::vector<std::string>& visible_contact_ids) override {}
 
   // NearbyShareService::Observer
+  void OnHighVisibilityChangeRequested() override;
   void OnHighVisibilityChanged(bool high_visibility_on) override;
   void OnShutdown() override;
 
diff --git a/chrome/browser/nearby_sharing/nearby_share_delegate_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_share_delegate_impl_unittest.cc
index 0aec2c8..738a563 100644
--- a/chrome/browser/nearby_sharing/nearby_share_delegate_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_share_delegate_impl_unittest.cc
@@ -151,6 +151,17 @@
   EXPECT_FALSE(delegate_.IsEnableHighVisibilityRequestActive());
 }
 
+TEST_F(NearbyShareDelegateImplTest, TestIsEnableOnHighVisibilityRequest) {
+  settings()->SetEnabled(true);
+
+  EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
+
+  delegate_.OnHighVisibilityChangeRequested();
+  EXPECT_TRUE(delegate_.IsEnableHighVisibilityRequestActive());
+  SetHighVisibilityOn(true);
+  EXPECT_FALSE(delegate_.IsEnableHighVisibilityRequestActive());
+}
+
 TEST_F(NearbyShareDelegateImplTest, ShowOnboardingAndTurnOnHighVisibility) {
   settings()->SetEnabled(false);
 
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service.h b/chrome/browser/nearby_sharing/nearby_sharing_service.h
index 6785f44..866a230 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service.h
@@ -70,6 +70,7 @@
 
   class Observer : public base::CheckedObserver {
    public:
+    virtual void OnHighVisibilityChangeRequested() {}
     virtual void OnHighVisibilityChanged(bool in_high_visibility) = 0;
 
     // Called during the |KeyedService| shutdown, but before everything has been
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index 3fac16c..e01ba55 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -1643,11 +1643,22 @@
   // updated API referenced in the bug which allows setting a per-advertisement
   // interval.
 
+  // TODO(crbug/1155669): This will suppress the system notification that
+  // alerts the user that their device is discoverable, but it exposes Nearby
+  // Share logic to external components. We should clean this up with a better
+  // abstraction.
+  bool used_device_name = device_name.has_value();
+  if (used_device_name) {
+    for (auto& observer : observers_) {
+      observer.OnHighVisibilityChangeRequested();
+    }
+  }
+
   nearby_connections_manager_->StartAdvertising(
       *endpoint_info,
       /*listener=*/this, power_level, data_usage,
       base::BindOnce(&NearbySharingServiceImpl::OnStartAdvertisingResult,
-                     weak_ptr_factory_.GetWeakPtr(), device_name.has_value()));
+                     weak_ptr_factory_.GetWeakPtr(), used_device_name));
 
   advertising_power_level_ = power_level;
   NS_LOG(VERBOSE) << __func__
diff --git a/chrome/browser/optimization_guide/android/javatests/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuideBridgeFactoryUnitTest.java b/chrome/browser/optimization_guide/android/javatests/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuideBridgeFactoryUnitTest.java
index 41806f3..4ad16d7 100644
--- a/chrome/browser/optimization_guide/android/javatests/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuideBridgeFactoryUnitTest.java
+++ b/chrome/browser/optimization_guide/android/javatests/src/org/chromium/chrome/browser/optimization_guide/OptimizationGuideBridgeFactoryUnitTest.java
@@ -34,7 +34,7 @@
  * Unit tests for OptimizationGuideBridgeFactory
  */
 @RunWith(BaseJUnit4ClassRunner.class)
-@Batch(Batch.UNIT_TESTS)
+@Batch(Batch.PER_CLASS)
 public class OptimizationGuideBridgeFactoryUnitTest {
     @Rule
     public JniMocker mocker = new JniMocker();
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
index 847f852b..19679bda 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -25,8 +25,6 @@
 #include "chrome/browser/navigation_predictor/navigation_predictor_keyed_service.h"
 #include "chrome/browser/navigation_predictor/navigation_predictor_keyed_service_factory.h"
 #include "chrome/browser/optimization_guide/optimization_guide_navigation_data.h"
-#include "chrome/browser/optimization_guide/optimization_guide_permissions_util.h"
-#include "chrome/browser/optimization_guide/optimization_guide_web_contents_observer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/google/core/common/google_util.h"
 #include "components/optimization_guide/content/optimization_guide_decider.h"
@@ -39,6 +37,7 @@
 #include "components/optimization_guide/core/optimization_guide_constants.h"
 #include "components/optimization_guide/core/optimization_guide_enums.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_permissions_util.h"
 #include "components/optimization_guide/core/optimization_guide_prefs.h"
 #include "components/optimization_guide/core/optimization_guide_store.h"
 #include "components/optimization_guide/core/optimization_guide_switches.h"
@@ -622,7 +621,8 @@
 
 void OptimizationGuideHintsManager::MaybeScheduleTopHostsHintsFetch() {
   if (!top_host_provider_ ||
-      !IsUserPermittedToFetchFromRemoteOptimizationGuide(profile_)) {
+      !optimization_guide::IsUserPermittedToFetchFromRemoteOptimizationGuide(
+          profile_->IsOffTheRecord(), pref_service_)) {
     return;
   }
 
@@ -1257,8 +1257,10 @@
   if (!HasOptimizationTypeToFetchFor())
     return false;
 
-  if (!IsUserPermittedToFetchFromRemoteOptimizationGuide(profile_))
+  if (!optimization_guide::IsUserPermittedToFetchFromRemoteOptimizationGuide(
+          profile_->IsOffTheRecord(), pref_service_)) {
     return false;
+  }
   DCHECK(!profile_->IsOffTheRecord());
 
   if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS())
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
index e900839c..900c4a6 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/optimization_guide/content/optimization_guide_decider.h"
 #include "components/optimization_guide/core/bloom_filter.h"
 #include "components/optimization_guide/core/hints_component_util.h"
@@ -33,6 +34,7 @@
 #include "components/optimization_guide/core/optimization_guide_switches.h"
 #include "components/optimization_guide/core/proto_database_provider_test_base.h"
 #include "components/optimization_guide/core/top_host_provider.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/public/test/browser_task_environment.h"
@@ -261,17 +263,19 @@
   }
 
   void TearDown() override {
-    optimization_guide::ProtoDatabaseProviderTestBase::TearDown();
     ResetHintsManager();
+    optimization_guide::ProtoDatabaseProviderTestBase::TearDown();
   }
 
   void CreateHintsManager(
       optimization_guide::TopHostProvider* top_host_provider) {
-    if (hints_manager_) {
+    if (hints_manager_)
       ResetHintsManager();
-    }
+
     pref_service_ = std::make_unique<TestingPrefServiceSimple>();
     optimization_guide::prefs::RegisterProfilePrefs(pref_service_->registry());
+    pref_service_->registry()->RegisterBooleanPref(
+        data_reduction_proxy::prefs::kDataSaverEnabled, false);
 
     url_loader_factory_ =
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
@@ -295,6 +299,7 @@
     hints_manager_->Shutdown();
     hints_manager_.reset();
     hint_store_.reset();
+    pref_service_.reset();
     RunUntilIdle();
   }
 
diff --git a/chrome/browser/optimization_guide/optimization_guide_permissions_util.cc b/chrome/browser/optimization_guide/optimization_guide_permissions_util.cc
deleted file mode 100644
index ebf24a9a..0000000
--- a/chrome/browser/optimization_guide/optimization_guide_permissions_util.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2019 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/optimization_guide/optimization_guide_permissions_util.h"
-
-#include <memory>
-
-#include "base/feature_list.h"
-#include "chrome/browser/performance_hints/performance_hints_features.h"
-#include "chrome/browser/previews/previews_service.h"
-#include "chrome/browser/previews/previews_service_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/optimization_guide/core/optimization_guide_features.h"
-#include "components/optimization_guide/core/optimization_guide_switches.h"
-#include "components/unified_consent/url_keyed_data_collection_consent_helper.h"
-
-namespace {
-
-bool IsUserDataSaverEnabledAndAllowedToFetchFromRemoteService(
-    Profile* profile) {
-  // Check if they are a data saver user.
-  if (!data_reduction_proxy::DataReductionProxySettings::
-          IsDataSaverEnabledByUser(profile->IsOffTheRecord(),
-                                   profile->GetPrefs())) {
-    return false;
-  }
-
-  // Now ensure that they have seen the HTTPS infobar notification.
-  PreviewsService* previews_service =
-      PreviewsServiceFactory::GetForProfile(profile);
-  if (!previews_service)
-    return false;
-
-  PreviewsHTTPSNotificationInfoBarDecider* info_bar_decider =
-      previews_service->previews_https_notification_infobar_decider();
-  return !info_bar_decider->NeedsToNotifyUser();
-}
-
-bool IsUserConsentedToAnonymousDataCollectionAndAllowedToFetchFromRemoteService(
-    Profile* profile) {
-  if (!optimization_guide::features::
-          IsRemoteFetchingForAnonymousDataConsentEnabled()) {
-    return false;
-  }
-
-  std::unique_ptr<unified_consent::UrlKeyedDataCollectionConsentHelper> helper =
-      unified_consent::UrlKeyedDataCollectionConsentHelper::
-          NewAnonymizedDataCollectionConsentHelper(profile->GetPrefs());
-  return helper->IsEnabled();
-}
-
-}  // namespace
-
-bool IsUserPermittedToFetchFromRemoteOptimizationGuide(Profile* profile) {
-  if (profile->IsOffTheRecord())
-    return false;
-
-  if (optimization_guide::switches::
-          ShouldOverrideCheckingUserPermissionsToFetchHintsForTesting()) {
-    return true;
-  }
-
-  if (!optimization_guide::features::IsRemoteFetchingEnabled())
-    return false;
-
-  if (performance_hints::features::
-          IsRemoteFetchingExplicitlyAllowedForPerformanceInfo())
-    return true;
-
-  if (IsUserDataSaverEnabledAndAllowedToFetchFromRemoteService(profile))
-    return true;
-
-  return IsUserConsentedToAnonymousDataCollectionAndAllowedToFetchFromRemoteService(
-      profile);
-}
diff --git a/chrome/browser/optimization_guide/optimization_guide_permissions_util.h b/chrome/browser/optimization_guide/optimization_guide_permissions_util.h
deleted file mode 100644
index 8c3fd199..0000000
--- a/chrome/browser/optimization_guide/optimization_guide_permissions_util.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2019 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_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_PERMISSIONS_UTIL_H_
-#define CHROME_BROWSER_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_PERMISSIONS_UTIL_H_
-
-class Profile;
-
-// Returns true if the user, as represented by |profile| is permitted to make
-// calls to the remote Optimization Guide Service.
-bool IsUserPermittedToFetchFromRemoteOptimizationGuide(Profile* profile);
-
-#endif  // CHROME_BROWSER_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_PERMISSIONS_UTIL_H_
diff --git a/chrome/browser/optimization_guide/optimization_guide_permissions_util_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_permissions_util_unittest.cc
deleted file mode 100644
index 3cc9d9c7..0000000
--- a/chrome/browser/optimization_guide/optimization_guide_permissions_util_unittest.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2019 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/optimization_guide/optimization_guide_permissions_util.h"
-
-#include "base/command_line.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/performance_hints/performance_hints_features.h"
-#include "chrome/browser/previews/previews_service.h"
-#include "chrome/browser/previews/previews_service_factory.h"
-#include "chrome/browser/unified_consent/unified_consent_service_factory.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/optimization_guide/core/optimization_guide_features.h"
-#include "components/previews/core/previews_switches.h"
-#include "components/sync/driver/sync_driver_switches.h"
-#include "components/unified_consent/unified_consent_service.h"
-
-class OptimizationGuidePermissionsUtilTest
-    : public ChromeRenderViewHostTestHarness {
- public:
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-
-    drp_test_context_ =
-        data_reduction_proxy::DataReductionProxyTestContext::Builder()
-            .WithMockConfig()
-            .Build();
-  }
-
-  void TearDown() override {
-    drp_test_context_->DestroySettings();
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
-  void SetDataSaverEnabled(bool enabled) {
-    drp_test_context_->SetDataReductionProxyEnabled(enabled);
-  }
-
-  void SetInfobarSeen(bool has_seen_infobar) {
-    // Make sure infobar not shown.
-    PreviewsService* previews_service =
-        PreviewsServiceFactory::GetForProfile(profile());
-    PreviewsHTTPSNotificationInfoBarDecider* decider =
-        previews_service->previews_https_notification_infobar_decider();
-    // Initialize settings here so |decider| checks for the Data Saver bit.
-    decider->OnSettingsInitialized();
-    if (has_seen_infobar) {
-      base::CommandLine::ForCurrentProcess()->AppendSwitch(
-          previews::switches::kDoNotRequireLitePageRedirectInfoBar);
-    } else {
-      base::CommandLine::ForCurrentProcess()->RemoveSwitch(
-          previews::switches::kDoNotRequireLitePageRedirectInfoBar);
-    }
-  }
-
-  void SetSyncServiceEnabled(bool enabled) {
-    if (enabled) {
-      base::CommandLine::ForCurrentProcess()->RemoveSwitch(
-          switches::kDisableSync);
-    } else {
-      base::CommandLine::ForCurrentProcess()->AppendSwitch(
-          switches::kDisableSync);
-    }
-  }
-
-  void SetUrlKeyedAnonymizedDataCollectionEnabled(bool enabled) {
-    unified_consent::UnifiedConsentService* consent_service =
-        UnifiedConsentServiceFactory::GetForProfile(profile());
-    consent_service->SetUrlKeyedAnonymizedDataCollectionEnabled(enabled);
-  }
-
- private:
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyTestContext>
-      drp_test_context_;
-};
-
-TEST_F(OptimizationGuidePermissionsUtilTest,
-       IsUserPermittedToFetchHintsNonDataSaverUser) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching});
-  SetDataSaverEnabled(false);
-  SetInfobarSeen(true);
-
-  EXPECT_FALSE(profile()->IsOffTheRecord());
-  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(OptimizationGuidePermissionsUtilTest,
-       IsUserPermittedToFetchHintsDataSaverUserInfobarNotSeen) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching});
-  SetDataSaverEnabled(true);
-  SetInfobarSeen(false);
-
-  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(OptimizationGuidePermissionsUtilTest,
-       IsUserPermittedToFetchHintsDataSaverUserInfobarSeen) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching});
-  SetDataSaverEnabled(true);
-  SetInfobarSeen(true);
-
-  EXPECT_FALSE(profile()->IsOffTheRecord());
-  EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(
-    OptimizationGuidePermissionsUtilTest,
-    IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionEnabledFeatureEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching,
-       optimization_guide::features::
-           kRemoteOptimizationGuideFetchingAnonymousDataConsent},
-      {});
-  SetDataSaverEnabled(false);
-  SetSyncServiceEnabled(true);
-  SetUrlKeyedAnonymizedDataCollectionEnabled(true);
-
-  EXPECT_FALSE(profile()->IsOffTheRecord());
-  EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(OptimizationGuidePermissionsUtilTest,
-       IsUserPermittedToFetchHintsNonDataSaverUserSyncDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching,
-       optimization_guide::features::
-           kRemoteOptimizationGuideFetchingAnonymousDataConsent},
-      {});
-  SetDataSaverEnabled(false);
-  SetSyncServiceEnabled(false);
-
-  EXPECT_FALSE(profile()->IsOffTheRecord());
-  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(
-    OptimizationGuidePermissionsUtilTest,
-    IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching,
-       optimization_guide::features::
-           kRemoteOptimizationGuideFetchingAnonymousDataConsent},
-      {});
-  SetDataSaverEnabled(false);
-  SetSyncServiceEnabled(true);
-  SetUrlKeyedAnonymizedDataCollectionEnabled(false);
-
-  EXPECT_FALSE(profile()->IsOffTheRecord());
-  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(
-    OptimizationGuidePermissionsUtilTest,
-    IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionEnabledFeatureNotEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching},
-      {optimization_guide::features::
-           kRemoteOptimizationGuideFetchingAnonymousDataConsent});
-  SetDataSaverEnabled(false);
-  SetSyncServiceEnabled(true);
-  SetUrlKeyedAnonymizedDataCollectionEnabled(true);
-
-  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(OptimizationGuidePermissionsUtilTest,
-       IsUserPermittedToFetchHintsAllConsentsEnabledButHintsFetchingDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {}, {optimization_guide::features::kRemoteOptimizationGuideFetching});
-  SetDataSaverEnabled(true);
-  SetInfobarSeen(true);
-  SetSyncServiceEnabled(true);
-  SetUrlKeyedAnonymizedDataCollectionEnabled(true);
-
-  EXPECT_FALSE(profile()->IsOffTheRecord());
-  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(OptimizationGuidePermissionsUtilTest,
-       IsUserPermittedToFetchHintsPerformanceInfoFlagExplicitlyAllows) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching,
-       performance_hints::features::
-           kContextMenuPerformanceInfoAndRemoteHintFetching},
-      {});
-  SetDataSaverEnabled(false);
-  SetSyncServiceEnabled(false);
-
-  EXPECT_FALSE(profile()->IsOffTheRecord());
-  EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
-}
-
-TEST_F(OptimizationGuidePermissionsUtilTest,
-       IsUserPermittedToFetchHintsAllConsentsEnabledIncognitoProfile) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching,
-       optimization_guide::features::
-           kRemoteOptimizationGuideFetchingAnonymousDataConsent,
-       performance_hints::features::
-           kContextMenuPerformanceInfoAndRemoteHintFetching},
-      {});
-  SetDataSaverEnabled(true);
-  SetInfobarSeen(true);
-  SetSyncServiceEnabled(true);
-  SetUrlKeyedAnonymizedDataCollectionEnabled(true);
-
-  Profile* incognito_profile = profile()->GetPrimaryOTRProfile();
-  EXPECT_TRUE(incognito_profile->IsOffTheRecord());
-  EXPECT_FALSE(
-      IsUserPermittedToFetchFromRemoteOptimizationGuide(incognito_profile));
-}
diff --git a/chrome/browser/optimization_guide/optimization_guide_top_host_provider.cc b/chrome/browser/optimization_guide/optimization_guide_top_host_provider.cc
index 284b325..d3e6a2f 100644
--- a/chrome/browser/optimization_guide/optimization_guide_top_host_provider.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_top_host_provider.cc
@@ -9,10 +9,10 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "base/values.h"
-#include "chrome/browser/optimization_guide/optimization_guide_permissions_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/optimization_guide/core/hints_processing_util.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_permissions_util.h"
 #include "components/optimization_guide/core/optimization_guide_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
@@ -100,8 +100,9 @@
 std::unique_ptr<OptimizationGuideTopHostProvider>
 OptimizationGuideTopHostProvider::CreateIfAllowed(
     content::BrowserContext* browser_context) {
-  if (IsUserPermittedToFetchFromRemoteOptimizationGuide(
-          Profile::FromBrowserContext(browser_context))) {
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+  if (optimization_guide::IsUserPermittedToFetchFromRemoteOptimizationGuide(
+          profile->IsOffTheRecord(), profile->GetPrefs())) {
     return base::WrapUnique(new OptimizationGuideTopHostProvider(
         browser_context, base::DefaultClock::GetInstance()));
   }
@@ -211,7 +212,8 @@
   PrefService* pref_service = profile->GetPrefs();
 
   bool is_user_permitted_to_fetch_hints =
-      IsUserPermittedToFetchFromRemoteOptimizationGuide(profile);
+      optimization_guide::IsUserPermittedToFetchFromRemoteOptimizationGuide(
+          profile->IsOffTheRecord(), pref_service);
   if (!is_user_permitted_to_fetch_hints) {
     // User toggled state during the session. Make sure the blacklist is
     // cleared.
@@ -253,7 +255,8 @@
   Profile* profile = Profile::FromBrowserContext(browser_context_);
 
   // The user toggled state during the session. Return empty.
-  if (!IsUserPermittedToFetchFromRemoteOptimizationGuide(profile))
+  if (!optimization_guide::IsUserPermittedToFetchFromRemoteOptimizationGuide(
+          profile->IsOffTheRecord(), pref_service_))
     return std::vector<std::string>();
 
   // It's possible that the blacklist is initialized but
diff --git a/chrome/browser/optimization_guide/optimization_guide_top_host_provider_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_top_host_provider_unittest.cc
index 2185318..9ac09b3 100644
--- a/chrome/browser/optimization_guide/optimization_guide_top_host_provider_unittest.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_top_host_provider_unittest.cc
@@ -8,10 +8,6 @@
 #include "base/test/simple_test_clock.h"
 #include "base/time/default_clock.h"
 #include "base/values.h"
-#include "chrome/browser/previews/previews_https_notification_infobar_decider.h"
-#include "chrome/browser/previews/previews_service.h"
-#include "chrome/browser/previews/previews_service_factory.h"
-#include "chrome/browser/previews/previews_ui_tab_helper.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
@@ -195,65 +191,24 @@
   ASSERT_FALSE(OptimizationGuideTopHostProvider::CreateIfAllowed(profile()));
 }
 
-TEST_F(OptimizationGuideTopHostProviderTest,
-       CreateIfAllowedDataSaverUserInfobarNotSeen) {
+TEST_F(OptimizationGuideTopHostProviderTest, CreateIfAllowedDataSaverUser) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       {optimization_guide::features::kRemoteOptimizationGuideFetching});
 
   SetDataSaverEnabled(true);
 
-  // Make sure infobar not shown.
-  PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile(
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
-  PreviewsHTTPSNotificationInfoBarDecider* decider =
-      previews_service->previews_https_notification_infobar_decider();
-  // Initialize settings here so |decider| checks for the Data Saver bit.
-  decider->OnSettingsInitialized();
-  EXPECT_TRUE(decider->NeedsToNotifyUser());
-
-  ASSERT_FALSE(OptimizationGuideTopHostProvider::CreateIfAllowed(profile()));
-}
-
-TEST_F(OptimizationGuideTopHostProviderTest,
-       CreateIfAllowedDataSaverUserInfobarSeen) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      {optimization_guide::features::kRemoteOptimizationGuideFetching});
-
-  SetDataSaverEnabled(true);
-
-  // Navigate so infobar is shown.
-  PreviewsUITabHelper::CreateForWebContents(web_contents());
-  PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile(
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
-  PreviewsHTTPSNotificationInfoBarDecider* decider =
-      previews_service->previews_https_notification_infobar_decider();
-  content::WebContentsTester::For(web_contents())
-      ->NavigateAndCommit(GURL("http://whatever.com"));
-  EXPECT_FALSE(decider->NeedsToNotifyUser());
-
   ASSERT_TRUE(OptimizationGuideTopHostProvider::CreateIfAllowed(profile()));
 }
 
 TEST_F(OptimizationGuideTopHostProviderTest,
-       CreateIfAllowedDataSaverUserInfobarSeenButHintsFetchingNotEnabled) {
+       CreateIfAllowedDataSaverUserButHintsFetchingNotEnabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
       {}, {optimization_guide::features::kRemoteOptimizationGuideFetching});
 
   SetDataSaverEnabled(true);
 
-  // Navigate so infobar is shown.
-  PreviewsUITabHelper::CreateForWebContents(web_contents());
-  PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile(
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
-  PreviewsHTTPSNotificationInfoBarDecider* decider =
-      previews_service->previews_https_notification_infobar_decider();
-  content::WebContentsTester::For(web_contents())
-      ->NavigateAndCommit(GURL("http://whatever.com"));
-  EXPECT_FALSE(decider->NeedsToNotifyUser());
-
   ASSERT_FALSE(OptimizationGuideTopHostProvider::CreateIfAllowed(profile()));
 }
 
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager.cc b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
index b31581ce..b348a84e 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/optimization_guide/optimization_guide_navigation_data.h"
-#include "chrome/browser/optimization_guide/optimization_guide_permissions_util.h"
 #include "chrome/browser/optimization_guide/prediction/prediction_model_download_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_key.h"
@@ -33,6 +32,7 @@
 #include "components/optimization_guide/core/optimization_guide_constants.h"
 #include "components/optimization_guide/core/optimization_guide_enums.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_permissions_util.h"
 #include "components/optimization_guide/core/optimization_guide_prefs.h"
 #include "components/optimization_guide/core/optimization_guide_store.h"
 #include "components/optimization_guide/core/optimization_guide_switches.h"
@@ -629,7 +629,8 @@
   // Top hosts and active field trials convey some sort of user information, so
   // ensure that the user has opted into the right permissions before adding
   // these fields to the request.
-  if (IsUserPermittedToFetchFromRemoteOptimizationGuide(profile_)) {
+  if (IsUserPermittedToFetchFromRemoteOptimizationGuide(
+          profile_->IsOffTheRecord(), pref_service_)) {
     if (top_host_provider_) {
       top_hosts = top_host_provider_->GetTopHosts();
 
diff --git a/chrome/browser/password_manager/android/BUILD.gn b/chrome/browser/password_manager/android/BUILD.gn
index aac2d9d5..e04d268c 100644
--- a/chrome/browser/password_manager/android/BUILD.gn
+++ b/chrome/browser/password_manager/android/BUILD.gn
@@ -12,10 +12,13 @@
     "//components/password_manager/core/browser:password_manager_java_enums",
     "//third_party/android_deps:androidx_annotation_annotation_java",
     "//third_party/android_deps:androidx_fragment_fragment_java",
+    "//url:gurl_java",
   ]
   sources = [
     "java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java",
     "java/src/org/chromium/chrome/browser/password_manager/PasswordScriptsFetcherBridge.java",
+    "java/src/org/chromium/chrome/browser/password_manager/PasswordStoreBridge.java",
+    "java/src/org/chromium/chrome/browser/password_manager/PasswordStoreCredential.java",
     "java/src/org/chromium/chrome/browser/password_manager/settings/PasswordReauthenticationFragment.java",
     "java/src/org/chromium/chrome/browser/password_manager/settings/ReauthenticationManager.java",
   ]
@@ -24,7 +27,11 @@
 
 generate_jni("jni_headers") {
   visibility = [ "//chrome/browser" ]
-  sources = [ "java/src/org/chromium/chrome/browser/password_manager/PasswordScriptsFetcherBridge.java" ]
+  sources = [
+    "java/src/org/chromium/chrome/browser/password_manager/PasswordScriptsFetcherBridge.java",
+    "java/src/org/chromium/chrome/browser/password_manager/PasswordStoreBridge.java",
+    "java/src/org/chromium/chrome/browser/password_manager/PasswordStoreCredential.java",
+  ]
 }
 
 junit_binary("password_manager_junit_tests") {
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreBridge.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreBridge.java
new file mode 100644
index 0000000..596cdf9
--- /dev/null
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreBridge.java
@@ -0,0 +1,136 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.password_manager;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.url.GURL;
+
+/**
+ * Class handling communication with C++ password store from Java. It forwards
+ * messages to and from its C++ counterpart.
+ */
+public class PasswordStoreBridge {
+    @CalledByNative
+    private static PasswordStoreCredential createPasswordStoreCredential(
+            GURL url, String username, String password) {
+        return new PasswordStoreCredential(url, username, password);
+    }
+
+    private long mNativePasswordStoreBridge;
+    private final PasswordStoreObserver mPasswordStoreObserver;
+
+    /**
+     * Observer listening to messages relevant to password store changes.
+     */
+    public interface PasswordStoreObserver {
+        /**
+         * Called when the set of password credentials is changed.
+         *
+         * @param count The total number of stored password credentials.
+         */
+        void onSavedPasswordsChanged(int count);
+
+        /**
+         * Called when a stored credential has been updated.
+         *
+         * @param credential Credential updated.
+         */
+        void onEdit(PasswordStoreCredential credential);
+    }
+
+    /**
+     * Initializes its native counterpart.
+     */
+    public PasswordStoreBridge(PasswordStoreObserver passwordStoreObserver) {
+        mNativePasswordStoreBridge = PasswordStoreBridgeJni.get().init(this);
+        mPasswordStoreObserver = passwordStoreObserver;
+    }
+
+    @CalledByNative
+    private void passwordListAvailable(int count) {
+        mPasswordStoreObserver.onSavedPasswordsChanged(count);
+    }
+
+    @CalledByNative
+    private void onEditCredential(PasswordStoreCredential credential) {
+        mPasswordStoreObserver.onEdit(credential);
+    }
+
+    @CalledByNative
+    private static void insertCredential(PasswordStoreCredential[] credentials, int index, GURL url,
+            String username, String password) {
+        credentials[index] = new PasswordStoreCredential(url, username, password);
+    }
+
+    /**
+     * Inserts new credential into the password store.
+     */
+    public void insertPasswordCredential(PasswordStoreCredential credential) {
+        PasswordStoreBridgeJni.get().insertPasswordCredential(
+                mNativePasswordStoreBridge, credential);
+    }
+
+    /**
+     * Updates an existing credential with a new password.
+     *
+     * @return True if credential was successfully updated, false otherwise.
+     */
+    public boolean editPassword(PasswordStoreCredential credential, String newPassword) {
+        return PasswordStoreBridgeJni.get().editPassword(
+                mNativePasswordStoreBridge, credential, newPassword);
+    }
+
+    /**
+     * Returns the count of stored credentials.
+     */
+    public int getPasswordStoreCredentialsCount() {
+        return PasswordStoreBridgeJni.get().getPasswordStoreCredentialsCount(
+                mNativePasswordStoreBridge);
+    }
+
+    /**
+     * Returns the list of credentials stored in the database.
+     *
+     * @param credentials array to be populated.
+     */
+    public void getAllCredentials(PasswordStoreCredential[] credentials) {
+        PasswordStoreBridgeJni.get().getAllCredentials(mNativePasswordStoreBridge, credentials);
+    }
+
+    /**
+     * Empties the password store.
+     */
+    public void clearAllPasswords() {
+        PasswordStoreBridgeJni.get().clearAllPasswords(mNativePasswordStoreBridge);
+    }
+
+    /**
+     * Destroys its C++ counterpart.
+     */
+    public void destroy() {
+        if (mNativePasswordStoreBridge != 0) {
+            PasswordStoreBridgeJni.get().destroy(mNativePasswordStoreBridge);
+            mNativePasswordStoreBridge = 0;
+        }
+    }
+
+    /**
+     * C++ method signatures.
+     */
+    @NativeMethods
+    interface Natives {
+        long init(PasswordStoreBridge passwordStoreBridge);
+        void insertPasswordCredential(
+                long nativePasswordStoreBridge, PasswordStoreCredential credential);
+        boolean editPassword(long nativePasswordStoreBridge, PasswordStoreCredential credential,
+                String newPassword);
+        int getPasswordStoreCredentialsCount(long nativePasswordStoreBridge);
+        void getAllCredentials(
+                long nativePasswordStoreBridge, PasswordStoreCredential[] credentials);
+        void clearAllPasswords(long nativePasswordStoreBridge);
+        void destroy(long nativePasswordStoreBridge);
+    }
+}
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreCredential.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreCredential.java
new file mode 100644
index 0000000..b625396
--- /dev/null
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreCredential.java
@@ -0,0 +1,48 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.password_manager;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.url.GURL;
+
+/**
+ * This class represents key elements of stored credential in the password store.
+ */
+public class PasswordStoreCredential {
+    private final GURL mUrl;
+    private final String mUsername;
+    private final String mPassword;
+
+    /**
+     * Constructs an instance of PasswordStoreCredential. Arguments should not be null.
+     *
+     * @param url The associated URL to this credential.
+     * @param username The username used to identify this credential.
+     * @param password The password associated to this credential.
+     */
+    public PasswordStoreCredential(GURL url, String username, String password) {
+        assert url != null;
+        assert username != null;
+        assert password != null;
+        mUrl = url;
+        mUsername = username;
+        mPassword = password;
+    }
+
+    @CalledByNative
+    public GURL getUrl() {
+        return mUrl;
+    }
+
+    @CalledByNative
+    public String getUsername() {
+        return mUsername;
+    }
+
+    @CalledByNative
+    public String getPassword() {
+        return mPassword;
+    }
+}
diff --git a/chrome/browser/password_manager/android/password_store_bridge.cc b/chrome/browser/password_manager/android/password_store_bridge.cc
new file mode 100644
index 0000000..20af6400
--- /dev/null
+++ b/chrome/browser/password_manager/android/password_store_bridge.cc
@@ -0,0 +1,116 @@
+// 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/password_manager/android/password_store_bridge.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/callback_helpers.h"
+#include "chrome/browser/password_manager/android/jni_headers/PasswordStoreBridge_jni.h"
+#include "chrome/browser/password_manager/android/jni_headers/PasswordStoreCredential_jni.h"
+#include "components/password_manager/core/browser/form_parsing/form_parser.h"
+#include "url/android/gurl_android.h"
+
+namespace {
+using password_manager::PasswordForm;
+using SavedPasswordsView =
+    password_manager::SavedPasswordsPresenter::SavedPasswordsView;
+
+PasswordForm ConvertJavaObjectToPasswordForm(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& credential) {
+  PasswordForm form;
+
+  form.url = *url::GURLAndroid::ToNativeGURL(
+      env, Java_PasswordStoreCredential_getUrl(env, credential));
+  form.signon_realm = password_manager::GetSignonRealm(form.url);
+  form.username_value = ConvertJavaStringToUTF16(
+      env, Java_PasswordStoreCredential_getUsername(env, credential));
+  form.password_value = ConvertJavaStringToUTF16(
+      env, Java_PasswordStoreCredential_getPassword(env, credential));
+
+  return form;
+}
+
+}  // namespace
+
+// static
+static jlong JNI_PasswordStoreBridge_Init(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& java_bridge) {
+  return reinterpret_cast<intptr_t>(new PasswordStoreBridge(java_bridge));
+}
+
+PasswordStoreBridge::PasswordStoreBridge(
+    const base::android::JavaParamRef<jobject>& java_bridge)
+    : java_bridge_(java_bridge) {
+  saved_passwords_presenter_.Init();
+  observed_saved_password_presenter_.Observe(&saved_passwords_presenter_);
+}
+
+PasswordStoreBridge::~PasswordStoreBridge() = default;
+
+void PasswordStoreBridge::InsertPasswordCredential(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& credential) {
+  password_store_->AddLogin(ConvertJavaObjectToPasswordForm(env, credential));
+}
+
+bool PasswordStoreBridge::EditPassword(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& credential,
+    const base::android::JavaParamRef<jstring>& new_password) {
+  return saved_passwords_presenter_.EditPassword(
+      ConvertJavaObjectToPasswordForm(env, credential),
+      ConvertJavaStringToUTF16(env, new_password));
+}
+
+jint PasswordStoreBridge::GetPasswordStoreCredentialsCount(JNIEnv* env) const {
+  return static_cast<int>(
+      saved_passwords_presenter_.GetSavedPasswords().size());
+}
+
+void PasswordStoreBridge::GetAllCredentials(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobjectArray>& java_credentials) const {
+  const auto credentials = saved_passwords_presenter_.GetSavedPasswords();
+  for (size_t i = 0; i < credentials.size(); ++i) {
+    const auto& credential = credentials[i];
+    Java_PasswordStoreBridge_insertCredential(
+        env, java_credentials, i,
+        url::GURLAndroid::FromNativeGURL(env, credential.url),
+        base::android::ConvertUTF16ToJavaString(env, credential.username_value),
+        base::android::ConvertUTF16ToJavaString(env,
+                                                credential.password_value));
+  }
+}
+
+void PasswordStoreBridge::ClearAllPasswords(JNIEnv* env) {
+  password_store_->ClearStore(base::DoNothing());
+}
+
+void PasswordStoreBridge::Destroy(JNIEnv* env) {
+  delete this;
+}
+
+void PasswordStoreBridge::OnSavedPasswordsChanged(
+    SavedPasswordsView passwords) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  // Notifies java counter side that a new set of credentials is available.
+  Java_PasswordStoreBridge_passwordListAvailable(
+      env, java_bridge_, static_cast<int>(passwords.size()));
+}
+
+void PasswordStoreBridge::OnEdited(const PasswordForm& form) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  // Notifies java counter side that a credential has been edited.
+  Java_PasswordStoreBridge_onEditCredential(
+      env, java_bridge_,
+      Java_PasswordStoreBridge_createPasswordStoreCredential(
+          env, url::GURLAndroid::FromNativeGURL(env, form.url),
+          base::android::ConvertUTF16ToJavaString(env, form.username_value),
+          base::android::ConvertUTF16ToJavaString(env, form.password_value)));
+}
diff --git a/chrome/browser/password_manager/android/password_store_bridge.h b/chrome/browser/password_manager/android/password_store_bridge.h
new file mode 100644
index 0000000..d2fb07c0
--- /dev/null
+++ b/chrome/browser/password_manager/android/password_store_bridge.h
@@ -0,0 +1,79 @@
+// 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_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BRIDGE_H_
+#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BRIDGE_H_
+
+#include <jni.h>
+
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/scoped_observation.h"
+#include "chrome/browser/password_manager/password_store_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+
+class PasswordStoreBridge
+    : public password_manager::SavedPasswordsPresenter::Observer {
+ public:
+  explicit PasswordStoreBridge(
+      const base::android::JavaParamRef<jobject>& java_bridge);
+  ~PasswordStoreBridge() override;
+
+  PasswordStoreBridge(const PasswordStoreBridge&) = delete;
+  PasswordStoreBridge& operator=(const PasswordStoreBridge&) = delete;
+
+  // Called by Java to store a new credential into the password store.
+  void InsertPasswordCredential(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& credential);
+
+  // Called by Java to edit a credential.
+  bool EditPassword(JNIEnv* env,
+                    const base::android::JavaParamRef<jobject>& credential,
+                    const base::android::JavaParamRef<jstring>& new_password);
+
+  // Called by Java to get the number of stored credentials.
+  jint GetPasswordStoreCredentialsCount(JNIEnv* env) const;
+
+  // Called by Java to get all stored credentials.
+  void GetAllCredentials(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobjectArray>& java_credentials) const;
+
+  // Called by Java to clear all stored passwords.
+  void ClearAllPasswords(JNIEnv* env);
+
+  // Called by Java to destroy `this`.
+  void Destroy(JNIEnv* env);
+
+ private:
+  // SavedPasswordsPresenter::Observer:
+  void OnSavedPasswordsChanged(
+      password_manager::SavedPasswordsPresenter::SavedPasswordsView passwords)
+      override;
+
+  void OnEdited(const password_manager::PasswordForm& form) override;
+
+  // The corresponding java object.
+  base::android::ScopedJavaGlobalRef<jobject> java_bridge_;
+
+  // Handle to the password store, powering `saved_passwords_presenter_`.
+  scoped_refptr<password_manager::PasswordStore> password_store_ =
+      PasswordStoreFactory::GetForProfile(ProfileManager::GetLastUsedProfile(),
+                                          ServiceAccessType::EXPLICIT_ACCESS);
+
+  // Used to fetch and edit passwords.
+  password_manager::SavedPasswordsPresenter saved_passwords_presenter_{
+      password_store_};
+
+  // A scoped observer for |saved_passwords_presenter_|.
+  base::ScopedObservation<password_manager::SavedPasswordsPresenter,
+                          password_manager::SavedPasswordsPresenter::Observer>
+      observed_saved_password_presenter_{this};
+};
+
+#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BRIDGE_H_
diff --git a/chrome/browser/pdf/pdf_extension_util.cc b/chrome/browser/pdf/pdf_extension_util.cc
index e8d7947..bfc1eb6 100644
--- a/chrome/browser/pdf/pdf_extension_util.cc
+++ b/chrome/browser/pdf/pdf_extension_util.cc
@@ -71,6 +71,8 @@
     {"propertiesDialogClose", IDS_CLOSE},
     {"propertiesDialogTitle", IDS_PDF_PROPERTIES_DIALOG_TITLE},
     {"propertiesFastWebView", IDS_PDF_PROPERTIES_FAST_WEB_VIEW},
+    {"propertiesFastWebViewNo", IDS_PDF_PROPERTIES_FAST_WEB_VIEW_NO},
+    {"propertiesFastWebViewYes", IDS_PDF_PROPERTIES_FAST_WEB_VIEW_YES},
     {"propertiesFileName", IDS_PDF_PROPERTIES_FILE_NAME},
     {"propertiesFileSize", IDS_PDF_PROPERTIES_FILE_SIZE},
     {"propertiesKeywords", IDS_PDF_PROPERTIES_KEYWORDS},
diff --git a/chrome/browser/performance_hints/performance_hints_features.cc b/chrome/browser/performance_hints/performance_hints_features.cc
index 4c13c25..11854023 100644
--- a/chrome/browser/performance_hints/performance_hints_features.cc
+++ b/chrome/browser/performance_hints/performance_hints_features.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/performance_hints/performance_hints_features.h"
 
 #include "base/metrics/field_trial_params.h"
+#include "components/optimization_guide/core/optimization_guide_features.h"
 
 namespace performance_hints {
 namespace features {
@@ -27,9 +28,6 @@
 
 const base::Feature kContextMenuPerformanceInfo{
     "ContextMenuPerformanceInfo", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kContextMenuPerformanceInfoAndRemoteHintFetching{
-    "ContextMenuPerformanceInfoAndRemoteHintFetching",
-    base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kPageInfoPerformanceHints{
     "PageInfoPerformanceHints", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -61,13 +59,8 @@
 
 bool IsContextMenuPerformanceInfoEnabled() {
   return base::FeatureList::IsEnabled(kContextMenuPerformanceInfo) ||
-         base::FeatureList::IsEnabled(
-             kContextMenuPerformanceInfoAndRemoteHintFetching);
-}
-
-bool IsRemoteFetchingExplicitlyAllowedForPerformanceInfo() {
-  return base::FeatureList::IsEnabled(
-      kContextMenuPerformanceInfoAndRemoteHintFetching);
+         optimization_guide::features::
+             IsRemoteFetchingExplicitlyAllowedForPerformanceInfo();
 }
 
 }  // namespace features
diff --git a/chrome/browser/performance_hints/performance_hints_features.h b/chrome/browser/performance_hints/performance_hints_features.h
index 2db0f31..281272f 100644
--- a/chrome/browser/performance_hints/performance_hints_features.h
+++ b/chrome/browser/performance_hints/performance_hints_features.h
@@ -51,10 +51,6 @@
 // Returns true if performance info should be shown in the context menu.
 bool IsContextMenuPerformanceInfoEnabled();
 
-// Returns true if a feature that explicitly allows remote fetching has been
-// enabled.
-bool IsRemoteFetchingExplicitlyAllowedForPerformanceInfo();
-
 }  // namespace features
 }  // namespace performance_hints
 
diff --git a/chrome/browser/performance_hints/performance_hints_observer.cc b/chrome/browser/performance_hints/performance_hints_observer.cc
index 996306d1..df1aab4 100644
--- a/chrome/browser/performance_hints/performance_hints_observer.cc
+++ b/chrome/browser/performance_hints/performance_hints_observer.cc
@@ -12,9 +12,9 @@
 #include "build/build_config.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
-#include "chrome/browser/optimization_guide/optimization_guide_permissions_util.h"
 #include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/profiles/profile.h"
+#include "components/optimization_guide/core/optimization_guide_permissions_util.h"
 #include "components/optimization_guide/core/url_pattern_with_wildcards.h"
 #include "components/optimization_guide/proto/performance_hints_metadata.pb.h"
 #include "content/public/browser/navigation_handle.h"
@@ -148,7 +148,9 @@
 
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  if (!profile || !IsUserPermittedToFetchFromRemoteOptimizationGuide(profile)) {
+  if (!profile ||
+      !optimization_guide::IsUserPermittedToFetchFromRemoteOptimizationGuide(
+          profile->IsOffTheRecord(), profile->GetPrefs())) {
     // We can't get performance hints if OptimizationGuide can't fetch them.
     return PerformanceClass::PERFORMANCE_UNKNOWN;
   }
diff --git a/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc b/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc
index 693ceb9..37ee17f5 100644
--- a/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc
+++ b/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc
@@ -351,11 +351,11 @@
   invalidation_service_ =
       std::make_unique<invalidation::FCMInvalidationService>(
           identity_provider_.get(),
-          base::BindRepeating(&syncer::FCMNetworkHandler::Create,
+          base::BindRepeating(&invalidation::FCMNetworkHandler::Create,
                               g_browser_process->gcm_driver(),
                               device_instance_id_driver_.get()),
           base::BindRepeating(
-              &syncer::PerUserTopicSubscriptionManager::Create,
+              &invalidation::PerUserTopicSubscriptionManager::Create,
               identity_provider_.get(), g_browser_process->local_state(),
               base::RetainedRef(
                   g_browser_process->shared_url_loader_factory())),
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
index 8ff0569..7e17e098 100644
--- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -404,7 +404,7 @@
       base::Time::NowFromSystemTime() - base::Time::UnixEpoch();
 
   GetInvalidationServiceForSenderId(kPolicyFCMInvalidationSenderID)
-      ->EmitInvalidationForTest(syncer::Invalidation::Init(
+      ->EmitInvalidationForTest(invalidation::Invalidation::Init(
           policy_invalidation_topic, now.InMicroseconds() /* version */,
           "payload"));
   {
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
index 61342c8..1a3810e 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
@@ -254,18 +255,18 @@
 }
 
 void CloudPolicyInvalidator::OnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
+    invalidation::InvalidatorState state) {
   DCHECK(state_ == STARTED);
   DCHECK(thread_checker_.CalledOnValidThread());
-  invalidation_service_enabled_ = state == syncer::INVALIDATIONS_ENABLED;
+  invalidation_service_enabled_ = state == invalidation::INVALIDATIONS_ENABLED;
   UpdateInvalidationsEnabled();
 }
 
 void CloudPolicyInvalidator::OnIncomingInvalidation(
-    const syncer::TopicInvalidationMap& invalidation_map) {
+    const invalidation::TopicInvalidationMap& invalidation_map) {
   DCHECK(state_ == STARTED);
   DCHECK(thread_checker_.CalledOnValidThread());
-  const syncer::SingleObjectInvalidationSet& list =
+  const invalidation::SingleObjectInvalidationSet& list =
       invalidation_map.ForTopic(topic_);
   if (list.IsEmpty()) {
     NOTREACHED();
@@ -287,7 +288,8 @@
   return owner_name_;
 }
 
-bool CloudPolicyInvalidator::IsPublicTopic(const syncer::Topic& topic) const {
+bool CloudPolicyInvalidator::IsPublicTopic(
+    const invalidation::Topic& topic) const {
   return IsPublicInvalidationTopic(topic);
 }
 
@@ -343,7 +345,7 @@
 void CloudPolicyInvalidator::OnStoreError(CloudPolicyStore* store) {}
 
 void CloudPolicyInvalidator::HandleInvalidation(
-    const syncer::Invalidation& invalidation) {
+    const invalidation::Invalidation& invalidation) {
   // Ignore old invalidations.
   if (invalid_ && !invalidation.is_unknown_version() &&
       invalidation.version() <= invalidation_version_) {
@@ -394,7 +396,7 @@
 
   // Update invalidation state.
   invalid_ = true;
-  invalidation_.reset(new syncer::Invalidation(invalidation));
+  invalidation_ = std::make_unique<invalidation::Invalidation>(invalidation);
   invalidation_version_ = version;
 
   // In order to prevent the cloud policy server from becoming overwhelmed when
@@ -426,7 +428,7 @@
     const enterprise_management::PolicyData* policy) {
   // Create the Topic based on the policy data.
   // If the policy does not specify a Topic, then unregister.
-  syncer::Topic topic;
+  invalidation::Topic topic;
   if (!policy || !GetCloudPolicyTopicFromPolicy(*policy, &topic)) {
     Unregister();
     return;
@@ -438,7 +440,7 @@
     Register(topic);
 }
 
-void CloudPolicyInvalidator::Register(const syncer::Topic& topic) {
+void CloudPolicyInvalidator::Register(const invalidation::Topic& topic) {
   // Register this handler with the invalidation service if needed.
   if (!is_registered_) {
     OnInvalidatorStateChange(invalidation_service_->GetInvalidatorState());
@@ -469,8 +471,8 @@
   if (is_registered_) {
     if (invalid_)
       AcknowledgeInvalidation();
-    CHECK(invalidation_service_->UpdateInterestedTopics(this,
-                                                        syncer::TopicSet()));
+    CHECK(invalidation_service_->UpdateInterestedTopics(
+        this, invalidation::TopicSet()));
     invalidation_service_->UnregisterInvalidationHandler(this);
     is_registered_ = false;
     UpdateInvalidationsEnabled();
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.h b/chrome/browser/policy/cloud/cloud_policy_invalidator.h
index 454617fe..90e44b00 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator.h
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.h
@@ -35,7 +35,7 @@
 namespace policy {
 
 // Listens for and provides policy invalidations.
-class CloudPolicyInvalidator : public syncer::InvalidationHandler,
+class CloudPolicyInvalidator : public invalidation::InvalidationHandler,
                                public CloudPolicyCore::Observer,
                                public CloudPolicyStore::Observer {
  public:
@@ -116,12 +116,12 @@
     return invalidation_service_;
   }
 
-  // syncer::InvalidationHandler:
-  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  // invalidation::InvalidationHandler:
+  void OnInvalidatorStateChange(invalidation::InvalidatorState state) override;
   void OnIncomingInvalidation(
-      const syncer::TopicInvalidationMap& invalidation_map) override;
+      const invalidation::TopicInvalidationMap& invalidation_map) override;
   std::string GetOwnerName() const override;
-  bool IsPublicTopic(const syncer::Topic& topic) const override;
+  bool IsPublicTopic(const invalidation::Topic& topic) const override;
 
   // CloudPolicyCore::Observer:
   void OnCoreConnected(CloudPolicyCore* core) override;
@@ -134,7 +134,7 @@
 
  private:
   // Handle an invalidation to the policy.
-  void HandleInvalidation(const syncer::Invalidation& invalidation);
+  void HandleInvalidation(const invalidation::Invalidation& invalidation);
 
   // Update topic subscription with the invalidation service based on the
   // given policy data.
@@ -142,7 +142,7 @@
 
   // Registers this handler with |invalidation_service_| if needed and
   // subscribes to the given |topic| with the invalidation service.
-  void Register(const syncer::Topic& topic);
+  void Register(const invalidation::Topic& topic);
 
   // Unregisters this handler and unsubscribes from the current topic with
   // the invalidation service.
@@ -216,7 +216,7 @@
   bool is_registered_;
 
   // The topic representing the policy in the invalidation service.
-  syncer::Topic topic_;
+  invalidation::Topic topic_;
 
   // Whether the policy is current invalid. This is set to true when an
   // invalidation is received and reset when the policy fetched due to the
@@ -237,7 +237,7 @@
   int64_t highest_handled_invalidation_version_;
 
   // The most up to date invalidation.
-  std::unique_ptr<syncer::Invalidation> invalidation_;
+  std::unique_ptr<invalidation::Invalidation> invalidation_;
 
   // The maximum random delay, in ms, between receiving an invalidation and
   // fetching the new policy.
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
index 4094673..c2bad151 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
@@ -131,13 +131,14 @@
   void EnableInvalidationService();
 
   // Causes the invalidation service to fire an invalidation.
-  syncer::Invalidation FireInvalidation(PolicyObject object,
-                                        int64_t version,
-                                        const std::string& payload);
+  invalidation::Invalidation FireInvalidation(PolicyObject object,
+                                              int64_t version,
+                                              const std::string& payload);
 
   // Causes the invalidation service to fire an invalidation with unknown
   // version.
-  syncer::Invalidation FireUnknownVersionInvalidation(PolicyObject object);
+  invalidation::Invalidation FireUnknownVersionInvalidation(
+      PolicyObject object);
 
   // Checks the expected value of the currently set invalidation info.
   bool CheckInvalidationInfo(int64_t version, const std::string& payload);
@@ -151,7 +152,7 @@
   bool CheckPolicyRefreshed();
   bool CheckPolicyRefreshedWithUnknownVersion();
 
-  bool IsUnsent(const syncer::Invalidation& invalidation);
+  bool IsUnsent(const invalidation::Invalidation& invalidation);
 
   // Returns the invalidations enabled state set by the invalidator on the
   // refresh scheduler.
@@ -159,7 +160,8 @@
 
   // Determines if the invalidation with the given ack handle has been
   // acknowledged.
-  bool IsInvalidationAcknowledged(const syncer::Invalidation& invalidation);
+  bool IsInvalidationAcknowledged(
+      const invalidation::Invalidation& invalidation);
 
   // Determines if the invalidator has registered for an object with the
   // invalidation service.
@@ -194,7 +196,7 @@
   bool CheckPolicyRefreshCount(int count);
 
   // Returns the invalidation topic corresponding to the given policy object.
-  const syncer::Topic& GetPolicyTopic(PolicyObject object) const;
+  const invalidation::Topic& GetPolicyTopic(PolicyObject object) const;
 
   base::test::SingleThreadTaskEnvironment task_environment_;
 
@@ -210,8 +212,8 @@
   std::unique_ptr<CloudPolicyInvalidator> invalidator_;
 
   // Topics for the test policy objects.
-  syncer::Topic topic_a_;
-  syncer::Topic topic_b_;
+  invalidation::Topic topic_a_;
+  invalidation::Topic topic_b_;
 
   // Fake policy values which are alternated to cause the store to report a
   // changed policy.
@@ -321,28 +323,29 @@
 
 void CloudPolicyInvalidatorTestBase::DisableInvalidationService() {
   invalidation_service_.SetInvalidatorState(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
+      invalidation::TRANSIENT_INVALIDATION_ERROR);
 }
 
 void CloudPolicyInvalidatorTestBase::EnableInvalidationService() {
-  invalidation_service_.SetInvalidatorState(syncer::INVALIDATIONS_ENABLED);
+  invalidation_service_.SetInvalidatorState(
+      invalidation::INVALIDATIONS_ENABLED);
 }
 
-syncer::Invalidation CloudPolicyInvalidatorTestBase::FireInvalidation(
+invalidation::Invalidation CloudPolicyInvalidatorTestBase::FireInvalidation(
     PolicyObject object,
     int64_t version,
     const std::string& payload) {
-  syncer::Invalidation invalidation =
-      syncer::Invalidation::Init(GetPolicyTopic(object), version, payload);
+  invalidation::Invalidation invalidation = invalidation::Invalidation::Init(
+      GetPolicyTopic(object), version, payload);
   invalidation_service_.EmitInvalidationForTest(invalidation);
   return invalidation;
 }
 
-syncer::Invalidation
+invalidation::Invalidation
 CloudPolicyInvalidatorTestBase::FireUnknownVersionInvalidation(
     PolicyObject object) {
-  syncer::Invalidation invalidation =
-      syncer::Invalidation::InitUnknownVersion(GetPolicyTopic(object));
+  invalidation::Invalidation invalidation =
+      invalidation::Invalidation::InitUnknownVersion(GetPolicyTopic(object));
   invalidation_service_.EmitInvalidationForTest(invalidation);
   return invalidation;
 }
@@ -365,7 +368,7 @@
 }
 
 bool CloudPolicyInvalidatorTestBase::IsUnsent(
-    const syncer::Invalidation& invalidation) {
+    const invalidation::Invalidation& invalidation) {
   return invalidation_service_.GetMockAckHandler()->IsUnsent(invalidation);
 }
 
@@ -379,7 +382,7 @@
 }
 
 bool CloudPolicyInvalidatorTestBase::IsInvalidationAcknowledged(
-    const syncer::Invalidation& invalidation) {
+    const invalidation::Invalidation& invalidation) {
   // The acknowledgement task is run through a WeakHandle that posts back to our
   // own thread.  We need to run any posted tasks before we can check
   // acknowledgement status.
@@ -453,7 +456,7 @@
   return testing::Mock::VerifyAndClearExpectations(client_);
 }
 
-const syncer::Topic& CloudPolicyInvalidatorTestBase::GetPolicyTopic(
+const invalidation::Topic& CloudPolicyInvalidatorTestBase::GetPolicyTopic(
     PolicyObject object) const {
   EXPECT_TRUE(object == POLICY_OBJECT_A || object == POLICY_OBJECT_B);
   return object == POLICY_OBJECT_A ? topic_a_ : topic_b_;
@@ -557,7 +560,8 @@
   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
   EXPECT_TRUE(IsUnsent(FireUnknownVersionInvalidation(POLICY_OBJECT_B)));
   EXPECT_TRUE(CheckPolicyNotRefreshed());
-  syncer::Invalidation inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
+  invalidation::Invalidation inv =
+      FireUnknownVersionInvalidation(POLICY_OBJECT_A);
 
   // Check re-registration for object B. Make sure the pending invalidation for
   // object A is acknowledged without making the callback.
@@ -586,7 +590,8 @@
   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
 
   // Check unregistration when store is loaded with no invalidation object id.
-  syncer::Invalidation inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
+  invalidation::Invalidation inv =
+      FireUnknownVersionInvalidation(POLICY_OBJECT_A);
   EXPECT_FALSE(IsInvalidationAcknowledged(inv));
   StorePolicy(POLICY_OBJECT_NONE);
   EXPECT_FALSE(IsInvalidatorRegistered());
@@ -610,7 +615,7 @@
   StorePolicy(POLICY_OBJECT_A);
   StartInvalidator();
   EXPECT_TRUE(InvalidationsEnabled());
-  syncer::Invalidation inv =
+  invalidation::Invalidation inv =
       FireInvalidation(POLICY_OBJECT_A, V(12), "test_payload");
 
   // Make sure client info is set as soon as the invalidation is received.
@@ -631,7 +636,8 @@
   // Register and fire invalidation with unknown version.
   StorePolicy(POLICY_OBJECT_A);
   StartInvalidator();
-  syncer::Invalidation inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
+  invalidation::Invalidation inv =
+      FireUnknownVersionInvalidation(POLICY_OBJECT_A);
 
   // Make sure client info is not set until after the invalidation callback is
   // made.
@@ -651,11 +657,14 @@
   // Generate multiple invalidations.
   StorePolicy(POLICY_OBJECT_A);
   StartInvalidator();
-  syncer::Invalidation inv1 = FireInvalidation(POLICY_OBJECT_A, V(1), "test1");
+  invalidation::Invalidation inv1 =
+      FireInvalidation(POLICY_OBJECT_A, V(1), "test1");
   EXPECT_TRUE(CheckInvalidationInfo(V(1), "test1"));
-  syncer::Invalidation inv2 = FireInvalidation(POLICY_OBJECT_A, V(2), "test2");
+  invalidation::Invalidation inv2 =
+      FireInvalidation(POLICY_OBJECT_A, V(2), "test2");
   EXPECT_TRUE(CheckInvalidationInfo(V(2), "test2"));
-  syncer::Invalidation inv3 = FireInvalidation(POLICY_OBJECT_A, V(3), "test3");
+  invalidation::Invalidation inv3 =
+      FireInvalidation(POLICY_OBJECT_A, V(3), "test3");
   EXPECT_TRUE(CheckInvalidationInfo(V(3), "test3"));
 
   // Make sure the replaced invalidations are acknowledged.
@@ -685,15 +694,18 @@
   // unique invalidation version numbers.
   StorePolicy(POLICY_OBJECT_A);
   StartInvalidator();
-  syncer::Invalidation inv1 = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
+  invalidation::Invalidation inv1 =
+      FireUnknownVersionInvalidation(POLICY_OBJECT_A);
   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
   EXPECT_TRUE(CheckInvalidationInfo(-1, std::string()));
-  syncer::Invalidation inv2 = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
+  invalidation::Invalidation inv2 =
+      FireUnknownVersionInvalidation(POLICY_OBJECT_A);
   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
   EXPECT_TRUE(CheckInvalidationInfo(-2, std::string()));
-  syncer::Invalidation inv3 = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
+  invalidation::Invalidation inv3 =
+      FireUnknownVersionInvalidation(POLICY_OBJECT_A);
   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
   EXPECT_TRUE(CheckInvalidationInfo(-3, std::string()));
@@ -722,14 +734,16 @@
 
   // Check that an invalidation whose version is lower than the highest handled
   // so far is acknowledged but ignored otherwise.
-  syncer::Invalidation inv1 = FireInvalidation(POLICY_OBJECT_A, V(1), "test1");
+  invalidation::Invalidation inv1 =
+      FireInvalidation(POLICY_OBJECT_A, V(1), "test1");
   EXPECT_TRUE(CheckPolicyNotRefreshed());
   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
   EXPECT_TRUE(IsInvalidationAcknowledged(inv1));
   EXPECT_EQ(V(2), GetHighestHandledInvalidationVersion());
 
   // Check that an invalidation with an unknown version is handled.
-  syncer::Invalidation inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A);
+  invalidation::Invalidation inv =
+      FireUnknownVersionInvalidation(POLICY_OBJECT_A);
   EXPECT_TRUE(CheckPolicyRefreshedWithUnknownVersion());
   EXPECT_TRUE(CheckInvalidationInfo(-1, std::string()));
   StorePolicy(POLICY_OBJECT_A, -1);
@@ -738,7 +752,8 @@
 
   // Check that an invalidation whose version matches the highest handled so far
   // is acknowledged but ignored otherwise.
-  syncer::Invalidation inv2 = FireInvalidation(POLICY_OBJECT_A, V(2), "test2");
+  invalidation::Invalidation inv2 =
+      FireInvalidation(POLICY_OBJECT_A, V(2), "test2");
   EXPECT_TRUE(CheckPolicyNotRefreshed());
   EXPECT_TRUE(CheckInvalidationInfo(0, std::string()));
   EXPECT_TRUE(IsInvalidationAcknowledged(inv2));
@@ -746,7 +761,8 @@
 
   // Check that an invalidation whose version is higher than the highest handled
   // so far is handled, causing a policy refresh.
-  syncer::Invalidation inv3 = FireInvalidation(POLICY_OBJECT_A, V(3), "test3");
+  invalidation::Invalidation inv3 =
+      FireInvalidation(POLICY_OBJECT_A, V(3), "test3");
   EXPECT_TRUE(CheckPolicyRefreshed());
   EXPECT_TRUE(CheckInvalidationInfo(V(3), "test3"));
   StorePolicy(POLICY_OBJECT_A, V(3));
@@ -758,7 +774,8 @@
   // Generate an invalidation.
   StorePolicy(POLICY_OBJECT_A);
   StartInvalidator();
-  syncer::Invalidation inv = FireInvalidation(POLICY_OBJECT_A, V(3), "test");
+  invalidation::Invalidation inv =
+      FireInvalidation(POLICY_OBJECT_A, V(3), "test");
 
   // Ensure that the policy is not refreshed and the invalidation is
   // acknowledged if the store is loaded with the latest version before the
@@ -774,7 +791,8 @@
   // Generate an invalidation.
   StorePolicy(POLICY_OBJECT_A);
   StartInvalidator();
-  syncer::Invalidation inv = FireInvalidation(POLICY_OBJECT_A, V(3), "test");
+  invalidation::Invalidation inv =
+      FireInvalidation(POLICY_OBJECT_A, V(3), "test");
 
   // Ensure that the policy refresh is not made after the invalidator is shut
   // down.
@@ -826,7 +844,8 @@
   // Generate an invalidation.
   StorePolicy(POLICY_OBJECT_A);
   StartInvalidator();
-  syncer::Invalidation inv = FireInvalidation(POLICY_OBJECT_A, V(1), "test");
+  invalidation::Invalidation inv =
+      FireInvalidation(POLICY_OBJECT_A, V(1), "test");
   EXPECT_TRUE(InvalidationsEnabled());
 
   // Ensure that the policy is not refreshed after disconnecting the core, but
@@ -1111,7 +1130,7 @@
   // should be ignored.
   base::Time time = Now() - (invalidation_timeouts::kMaxInvalidationTimeDelta +
                              base::TimeDelta::FromSeconds(300));
-  syncer::Invalidation inv =
+  invalidation::Invalidation inv =
       FireInvalidation(POLICY_OBJECT_A, GetVersion(time), "test");
   ASSERT_TRUE(IsInvalidationAcknowledged(inv));
   ASSERT_TRUE(CheckPolicyNotRefreshed());
diff --git a/chrome/browser/policy/cloud/policy_invalidation_util.cc b/chrome/browser/policy/cloud/policy_invalidation_util.cc
index 408dfe4..0eed5dd9 100644
--- a/chrome/browser/policy/cloud/policy_invalidation_util.cc
+++ b/chrome/browser/policy/cloud/policy_invalidation_util.cc
@@ -16,14 +16,14 @@
 
 }  // namespace
 
-bool IsPublicInvalidationTopic(const syncer::Topic& topic) {
+bool IsPublicInvalidationTopic(const invalidation::Topic& topic) {
   return base::StartsWith(topic, kFcmPolicyPublicTopicPrefix,
                           base::CompareCase::SENSITIVE);
 }
 
 bool GetCloudPolicyTopicFromPolicy(
     const enterprise_management::PolicyData& policy,
-    syncer::Topic* topic) {
+    invalidation::Topic* topic) {
   if (!policy.has_policy_invalidation_topic() ||
       policy.policy_invalidation_topic().empty()) {
     return false;
@@ -34,7 +34,7 @@
 
 bool GetRemoteCommandTopicFromPolicy(
     const enterprise_management::PolicyData& policy,
-    syncer::Topic* topic) {
+    invalidation::Topic* topic) {
   if (!policy.has_command_invalidation_topic() ||
       policy.command_invalidation_topic().empty()) {
     return false;
@@ -43,7 +43,7 @@
   return true;
 }
 
-bool IsInvalidationExpired(const syncer::Invalidation& invalidation,
+bool IsInvalidationExpired(const invalidation::Invalidation& invalidation,
                            const base::Time& last_fetch_time,
                            const base::Time& current_time) {
   // If the version is unknown, consider the invalidation invalid if the
diff --git a/chrome/browser/policy/cloud/policy_invalidation_util.h b/chrome/browser/policy/cloud/policy_invalidation_util.h
index 3a69e78f..b8e855a4 100644
--- a/chrome/browser/policy/cloud/policy_invalidation_util.h
+++ b/chrome/browser/policy/cloud/policy_invalidation_util.h
@@ -15,11 +15,11 @@
 
 }  // namespace enterprise_management
 
-namespace syncer {
+namespace invalidation {
 
 class Invalidation;
 
-}  // namespace syncer
+}  // namespace invalidation
 
 namespace policy {
 
@@ -47,22 +47,22 @@
 // addressed to topic "DeviceGuestModeEnabled". But if 2 clients with different
 // users subscribe to private topic "BOOKMARK", they will receive different set
 // of messages addressed to pair ("BOOKMARK", GAIA ID) respectievely.
-bool IsPublicInvalidationTopic(const syncer::Topic& topic);
+bool IsPublicInvalidationTopic(const invalidation::Topic& topic);
 
 // Returns true if |policy| has data about policy to invalidate, and saves
 // that data in |topic|, and false otherwise.
 bool GetCloudPolicyTopicFromPolicy(
     const enterprise_management::PolicyData& policy,
-    syncer::Topic* topic);
+    invalidation::Topic* topic);
 
 // The same as GetCloudPolicyTopicFromPolicy but gets the |topic| for
 // remote command.
 bool GetRemoteCommandTopicFromPolicy(
     const enterprise_management::PolicyData& policy,
-    syncer::Topic* topic);
+    invalidation::Topic* topic);
 
 // Determines if an invalidation is expired.
-bool IsInvalidationExpired(const syncer::Invalidation& invalidation,
+bool IsInvalidationExpired(const invalidation::Invalidation& invalidation,
                            const base::Time& last_fetch_time,
                            const base::Time& current_time);
 
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator.cc b/chrome/browser/policy/cloud/remote_commands_invalidator.cc
index 7fc95e2..d14db74 100644
--- a/chrome/browser/policy/cloud/remote_commands_invalidator.cc
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator.cc
@@ -70,23 +70,23 @@
 }
 
 void RemoteCommandsInvalidator::OnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
+    invalidation::InvalidatorState state) {
   DCHECK_EQ(STARTED, state_);
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  invalidation_service_enabled_ = state == syncer::INVALIDATIONS_ENABLED;
+  invalidation_service_enabled_ = state == invalidation::INVALIDATIONS_ENABLED;
   UpdateInvalidationsEnabled();
 }
 
 void RemoteCommandsInvalidator::OnIncomingInvalidation(
-    const syncer::TopicInvalidationMap& invalidation_map) {
+    const invalidation::TopicInvalidationMap& invalidation_map) {
   DCHECK_EQ(STARTED, state_);
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (!invalidation_service_enabled_)
     LOG(WARNING) << "Unexpected invalidation received.";
 
-  const syncer::SingleObjectInvalidationSet& list =
+  const invalidation::SingleObjectInvalidationSet& list =
       invalidation_map.ForTopic(topic_);
   if (list.IsEmpty()) {
     NOTREACHED();
@@ -105,7 +105,7 @@
 }
 
 bool RemoteCommandsInvalidator::IsPublicTopic(
-    const syncer::Topic& topic) const {
+    const invalidation::Topic& topic) const {
   return IsPublicInvalidationTopic(topic);
 }
 
@@ -118,7 +118,7 @@
 
   // Create the Topic based on the policy data.
   // If the policy does not specify the Topic, then unregister.
-  syncer::Topic topic;
+  invalidation::Topic topic;
   if (!policy || !GetRemoteCommandTopicFromPolicy(*policy, &topic)) {
     Unregister();
     return;
@@ -130,7 +130,7 @@
     Register(topic);
 }
 
-void RemoteCommandsInvalidator::Register(const syncer::Topic& topic) {
+void RemoteCommandsInvalidator::Register(const invalidation::Topic& topic) {
   // Register this handler with the invalidation service if needed.
   if (!is_registered_) {
     OnInvalidatorStateChange(invalidation_service_->GetInvalidatorState());
@@ -151,8 +151,8 @@
 
 void RemoteCommandsInvalidator::Unregister() {
   if (is_registered_) {
-    CHECK(invalidation_service_->UpdateInterestedTopics(this,
-                                                        syncer::TopicSet()));
+    CHECK(invalidation_service_->UpdateInterestedTopics(
+        this, invalidation::TopicSet()));
     invalidation_service_->UnregisterInvalidationHandler(this);
     is_registered_ = false;
     UpdateInvalidationsEnabled();
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator.h b/chrome/browser/policy/cloud/remote_commands_invalidator.h
index dd71c138..a639852 100644
--- a/chrome/browser/policy/cloud/remote_commands_invalidator.h
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator.h
@@ -15,9 +15,9 @@
 class InvalidationService;
 }  // namespace invalidation
 
-namespace syncer {
+namespace invalidation {
 class Invalidation;
-}  // namespace syncer
+}  // namespace invalidation
 
 namespace policy {
 
@@ -25,7 +25,7 @@
 // services. It's not interacting with CloudPolicyClient/CloudPolicyCore
 // directly, instead, it handles the interacting with invalidation service
 // only and leaves interfaces to integrate with subclasses.
-class RemoteCommandsInvalidator : public syncer::InvalidationHandler {
+class RemoteCommandsInvalidator : public invalidation::InvalidationHandler {
  public:
   explicit RemoteCommandsInvalidator(std::string owner_name);
   ~RemoteCommandsInvalidator() override;
@@ -54,12 +54,12 @@
   // Whether the invalidator currently has the ability to receive invalidations.
   bool invalidations_enabled() { return invalidations_enabled_; }
 
-  // syncer::InvalidationHandler:
-  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  // invalidation::InvalidationHandler:
+  void OnInvalidatorStateChange(invalidation::InvalidatorState state) override;
   void OnIncomingInvalidation(
-      const syncer::TopicInvalidationMap& invalidation_map) override;
+      const invalidation::TopicInvalidationMap& invalidation_map) override;
   std::string GetOwnerName() const override;
-  bool IsPublicTopic(const syncer::Topic& topic) const override;
+  bool IsPublicTopic(const invalidation::Topic& topic) const override;
 
  protected:
   virtual void OnInitialize() = 0;
@@ -70,7 +70,7 @@
   // Subclasses must override this method to implement the actual remote
   // commands fetch.
   virtual void DoRemoteCommandsFetch(
-      const syncer::Invalidation& invalidation) = 0;
+      const invalidation::Invalidation& invalidation) = 0;
 
   // Subclasses must call this function to set the topic for remote command
   // invalidations.
@@ -79,7 +79,7 @@
  private:
   // Registers this handler with |invalidation_service_| if needed and
   // subscribes to the given |topic| with the invalidation service.
-  void Register(const syncer::Topic& topic);
+  void Register(const invalidation::Topic& topic);
 
   // Unregisters this handler and unsubscribes from the current topic with
   // the invalidation service.
@@ -117,7 +117,7 @@
   bool is_registered_ = false;
 
   // The Topic representing the remote commands in the invalidation service.
-  syncer::Topic topic_;
+  invalidation::Topic topic_;
 
   // A thread checker to make sure that callbacks are invoked on the correct
   // thread.
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc
index 1644f99..b24ecec 100644
--- a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc
@@ -85,7 +85,7 @@
 }
 
 void RemoteCommandsInvalidatorImpl::DoRemoteCommandsFetch(
-    const syncer::Invalidation& invalidation) {
+    const invalidation::Invalidation& invalidation) {
   DCHECK(core_->remote_commands_service());
 
   RecordInvalidationMetric(invalidation);
@@ -114,7 +114,7 @@
 void RemoteCommandsInvalidatorImpl::OnStoreError(CloudPolicyStore* core) {}
 
 void RemoteCommandsInvalidatorImpl::RecordInvalidationMetric(
-    const syncer::Invalidation& invalidation) const {
+    const invalidation::Invalidation& invalidation) const {
   const auto last_fetch_time =
       base::Time::FromJavaTime(core_->store()->policy()->timestamp());
   const auto current_time = clock_->Now();
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h
index b8b2581..0be6252 100644
--- a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h
@@ -33,7 +33,8 @@
   void OnShutdown() override;
   void OnStart() override;
   void OnStop() override;
-  void DoRemoteCommandsFetch(const syncer::Invalidation& invalidation) override;
+  void DoRemoteCommandsFetch(
+      const invalidation::Invalidation& invalidation) override;
 
   // CloudPolicyCore::Observer:
   void OnCoreConnected(CloudPolicyCore* core) override;
@@ -46,7 +47,8 @@
   void OnStoreError(CloudPolicyStore* store) override;
 
  private:
-  void RecordInvalidationMetric(const syncer::Invalidation& invalidation) const;
+  void RecordInvalidationMetric(
+      const invalidation::Invalidation& invalidation) const;
 
   CloudPolicyCore* const core_;
 
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc b/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc
index 89e67ac..de4447f1 100644
--- a/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc
+++ b/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc
@@ -40,9 +40,9 @@
   MOCK_METHOD0(OnShutdown, void());
   MOCK_METHOD0(OnStart, void());
   MOCK_METHOD0(OnStop, void());
-  MOCK_METHOD1(DoRemoteCommandsFetch, void(const syncer::Invalidation&));
+  MOCK_METHOD1(DoRemoteCommandsFetch, void(const invalidation::Invalidation&));
 
-  void SetInvalidationTopic(const syncer::Topic& topic) {
+  void SetInvalidationTopic(const invalidation::Topic& topic) {
     em::PolicyData policy_data;
     policy_data.set_command_invalidation_topic(topic);
     ReloadPolicyData(&policy_data);
@@ -63,29 +63,33 @@
       : kTestingTopic1("abcdef"), kTestingTopic2("defabc") {}
 
   void EnableInvalidationService() {
-    invalidation_service_.SetInvalidatorState(syncer::INVALIDATIONS_ENABLED);
+    invalidation_service_.SetInvalidatorState(
+        invalidation::INVALIDATIONS_ENABLED);
   }
 
   void DisableInvalidationService() {
     invalidation_service_.SetInvalidatorState(
-        syncer::TRANSIENT_INVALIDATION_ERROR);
+        invalidation::TRANSIENT_INVALIDATION_ERROR);
   }
 
-  syncer::Invalidation CreateInvalidation(const syncer::Topic& topic) {
-    return syncer::Invalidation::InitUnknownVersion(topic);
+  invalidation::Invalidation CreateInvalidation(
+      const invalidation::Topic& topic) {
+    return invalidation::Invalidation::InitUnknownVersion(topic);
   }
 
-  syncer::Invalidation FireInvalidation(const syncer::Topic& topic) {
-    const syncer::Invalidation invalidation = CreateInvalidation(topic);
+  invalidation::Invalidation FireInvalidation(
+      const invalidation::Topic& topic) {
+    const invalidation::Invalidation invalidation = CreateInvalidation(topic);
     invalidation_service_.EmitInvalidationForTest(invalidation);
     return invalidation;
   }
 
-  bool IsInvalidationSent(const syncer::Invalidation& invalidation) {
+  bool IsInvalidationSent(const invalidation::Invalidation& invalidation) {
     return !invalidation_service_.GetMockAckHandler()->IsUnsent(invalidation);
   }
 
-  bool IsInvalidationAcknowledged(const syncer::Invalidation& invalidation) {
+  bool IsInvalidationAcknowledged(
+      const invalidation::Invalidation& invalidation) {
     return invalidation_service_.GetMockAckHandler()->IsAcknowledged(
         invalidation);
   }
@@ -123,22 +127,22 @@
   }
 
   // Fire an invalidation to verify that invalidation is not working.
-  void VerifyInvalidationDisabled(const syncer::Topic& topic) {
-    const syncer::Invalidation invalidation = FireInvalidation(topic);
+  void VerifyInvalidationDisabled(const invalidation::Topic& topic) {
+    const invalidation::Invalidation invalidation = FireInvalidation(topic);
 
     base::RunLoop().RunUntilIdle();
     EXPECT_FALSE(IsInvalidationSent(invalidation));
   }
 
   // Fire an invalidation to verify that invalidation works.
-  void VerifyInvalidationEnabled(const syncer::Topic& topic) {
+  void VerifyInvalidationEnabled(const invalidation::Topic& topic) {
     EXPECT_TRUE(invalidator_.invalidations_enabled());
 
     EXPECT_CALL(
         invalidator_,
         DoRemoteCommandsFetch(InvalidationsEqual(CreateInvalidation(topic))))
         .Times(1);
-    const syncer::Invalidation invalidation = FireInvalidation(topic);
+    const invalidation::Invalidation invalidation = FireInvalidation(topic);
 
     base::RunLoop().RunUntilIdle();
     EXPECT_TRUE(IsInvalidationSent(invalidation));
@@ -146,8 +150,8 @@
     VerifyExpectations();
   }
 
-  syncer::Topic kTestingTopic1;
-  syncer::Topic kTestingTopic2;
+  invalidation::Topic kTestingTopic1;
+  invalidation::Topic kTestingTopic2;
 
   base::test::SingleThreadTaskEnvironment task_environment_;
 
@@ -175,7 +179,8 @@
 
   // Fire an invalidation with different object id, no invalidation will be
   // received.
-  const syncer::Invalidation invalidation1 = FireInvalidation(kTestingTopic2);
+  const invalidation::Invalidation invalidation1 =
+      FireInvalidation(kTestingTopic2);
 
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsInvalidationSent(invalidation1));
@@ -186,7 +191,8 @@
   EXPECT_CALL(invalidator_, DoRemoteCommandsFetch(InvalidationsEqual(
                                 CreateInvalidation(kTestingTopic1))))
       .Times(1);
-  const syncer::Invalidation invalidation2 = FireInvalidation(kTestingTopic1);
+  const invalidation::Invalidation invalidation2 =
+      FireInvalidation(kTestingTopic1);
 
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsInvalidationSent(invalidation2));
diff --git a/chrome/browser/policy/extension_policy_browsertest.cc b/chrome/browser/policy/extension_policy_browsertest.cc
index 9eaa982..8893af1 100644
--- a/chrome/browser/policy/extension_policy_browsertest.cc
+++ b/chrome/browser/policy/extension_policy_browsertest.cc
@@ -40,7 +40,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/policy/policy_constants.h"
 #include "components/version_info/channel.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/result_codes.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index 48502cba..da516e12 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -614,13 +614,6 @@
     public static final String SETTINGS_DEVELOPER_TRACING_CATEGORIES = "tracing_categories";
     public static final String SETTINGS_DEVELOPER_TRACING_MODE = "tracing_mode";
 
-    /**
-     * SharedPreference name for the preference that disables signing out of Chrome.
-     * Signing out is forever disabled once Chrome signs the user in automatically
-     * if the device has a child account or if the device is an Android EDU device.
-     */
-    public static final String SETTINGS_SYNC_SIGN_OUT_ALLOWED = "auto_signed_in_school_account";
-
     public static final String SETTINGS_PRIVACY_OTHER_FORMS_OF_HISTORY_DIALOG_SHOWN =
             "org.chromium.chrome.browser.settings.privacy."
             + "PREF_OTHER_FORMS_OF_HISTORY_DIALOG_SHOWN";
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java
index dd508831..2f4700b 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java
@@ -146,7 +146,6 @@
                 ChromePreferenceKeys.SETTINGS_DEVELOPER_TRACING_CATEGORIES,
                 ChromePreferenceKeys.SETTINGS_DEVELOPER_TRACING_MODE,
                 ChromePreferenceKeys.SETTINGS_PRIVACY_OTHER_FORMS_OF_HISTORY_DIALOG_SHOWN,
-                ChromePreferenceKeys.SETTINGS_SYNC_SIGN_OUT_ALLOWED,
                 ChromePreferenceKeys.SETTINGS_WEBSITE_FAILED_BUILD_VERSION,
                 ChromePreferenceKeys.SHARING_LAST_SHARED_CLASS_NAME,
                 ChromePreferenceKeys.SHARING_LAST_SHARED_PACKAGE_NAME,
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 171c537..fb9c11ca 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -644,6 +644,8 @@
   GpuModeManager::RegisterPrefs(registry);
   signin::IdentityManager::RegisterLocalStatePrefs(registry);
   invalidation::FCMInvalidationService::RegisterPrefs(registry);
+  invalidation::InvalidatorRegistrarWithMemory::RegisterPrefs(registry);
+  invalidation::PerUserTopicSubscriptionManager::RegisterPrefs(registry);
   language::GeoLanguageProvider::RegisterLocalStatePrefs(registry);
   language::UlpLanguageCodeLocator::RegisterLocalStatePrefs(registry);
   memory::EnterpriseMemoryLimitPrefObserver::RegisterPrefs(registry);
@@ -664,8 +666,6 @@
   sessions::SessionIdGenerator::RegisterPrefs(registry);
   SSLConfigServiceManager::RegisterPrefs(registry);
   subresource_filter::IndexedRulesetVersion::RegisterPrefs(registry);
-  syncer::InvalidatorRegistrarWithMemory::RegisterPrefs(registry);
-  syncer::PerUserTopicSubscriptionManager::RegisterPrefs(registry);
   SystemNetworkContextManager::RegisterPrefs(registry);
   update_client::RegisterPrefs(registry);
   variations::VariationsService::RegisterPrefs(registry);
@@ -857,6 +857,8 @@
   image_fetcher::ImageCache::RegisterProfilePrefs(registry);
   site_engagement::ImportantSitesUtil::RegisterProfilePrefs(registry);
   IncognitoModePrefs::RegisterProfilePrefs(registry);
+  invalidation::PerUserTopicSubscriptionManager::RegisterProfilePrefs(registry);
+  invalidation::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry);
   language::LanguagePrefs::RegisterProfilePrefs(registry);
   login_detection::prefs::RegisterProfilePrefs(registry);
   lookalikes::RegisterProfilePrefs(registry);
@@ -899,8 +901,6 @@
   sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry);
   syncer::DeviceInfoPrefs::RegisterProfilePrefs(registry);
   syncer::SyncPrefs::RegisterProfilePrefs(registry);
-  syncer::PerUserTopicSubscriptionManager::RegisterProfilePrefs(registry);
-  syncer::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
   translate::TranslatePrefs::RegisterProfilePrefs(registry);
   omnibox::RegisterProfilePrefs(registry);
@@ -1043,6 +1043,7 @@
   SigninErrorNotifier::RegisterPrefs(registry);
   chromeos::ServicesCustomizationDocument::RegisterProfilePrefs(registry);
   chromeos::settings::OSSettingsUI::RegisterProfilePrefs(registry);
+  chromeos::StartupUtils::RegisterOobeProfilePrefs(registry);
   chromeos::UserImageSyncObserver::RegisterProfilePrefs(registry);
   crostini::prefs::RegisterProfilePrefs(registry);
   chromeos::attestation::TpmChallengeKey::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index 2d8bbdd5..97cae92b 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -393,7 +393,7 @@
 void PrintPreviewDialogController::OnInitiatorNavigated(
     WebContents* initiator,
     const content::LoadCommittedDetails& details) {
-  if (details.type == content::NAVIGATION_TYPE_EXISTING_PAGE) {
+  if (details.type == content::NAVIGATION_TYPE_EXISTING_ENTRY) {
     static const ui::PageTransition kTransitions[] = {
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR),
@@ -417,7 +417,7 @@
   // New |preview_dialog| is created. Don't update/erase map entry.
   if (waiting_for_new_preview_page_ &&
       ui::PageTransitionCoreTypeIs(type, ui::PAGE_TRANSITION_AUTO_TOPLEVEL) &&
-      details.type == content::NAVIGATION_TYPE_NEW_PAGE) {
+      details.type == content::NAVIGATION_TYPE_NEW_ENTRY) {
     waiting_for_new_preview_page_ = false;
     SaveInitiatorTitle(preview_dialog);
     return;
@@ -426,7 +426,7 @@
   // Cloud print sign-in causes a reload.
   if (!waiting_for_new_preview_page_ &&
       ui::PageTransitionCoreTypeIs(type, ui::PAGE_TRANSITION_RELOAD) &&
-      details.type == content::NAVIGATION_TYPE_EXISTING_PAGE &&
+      details.type == content::NAVIGATION_TYPE_EXISTING_ENTRY &&
       IsPrintPreviewURL(details.previous_main_frame_url)) {
     return;
   }
diff --git a/chrome/browser/printing/print_preview_dialog_controller.h b/chrome/browser/printing/print_preview_dialog_controller.h
index 351c0dfb..8f15ebd 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.h
+++ b/chrome/browser/printing/print_preview_dialog_controller.h
@@ -121,7 +121,7 @@
   PrintPreviewDialogMap preview_dialog_map_;
 
   // True if the controller is waiting for a new preview dialog via
-  // content::NAVIGATION_TYPE_NEW_PAGE.
+  // content::NAVIGATION_TYPE_NEW_ENTRY.
   bool waiting_for_new_preview_page_ = false;
 
   // Whether the PrintPreviewDialogController is in the middle of creating a
diff --git a/chrome/browser/profiles/android/profile_downloader_android.cc b/chrome/browser/profiles/android/profile_downloader_android.cc
index 3ea85b0..2d2513a 100644
--- a/chrome/browser/profiles/android/profile_downloader_android.cc
+++ b/chrome/browser/profiles/android/profile_downloader_android.cc
@@ -30,13 +30,11 @@
   AccountInfoRetriever(Profile* profile,
                        const CoreAccountId& account_id,
                        const std::string& email,
-                       const int desired_image_side_pixels,
-                       bool is_pre_signin)
+                       const int desired_image_side_pixels)
       : profile_(profile),
         account_id_(account_id),
         email_(email),
-        desired_image_side_pixels_(desired_image_side_pixels),
-        is_pre_signin_(is_pre_signin) {}
+        desired_image_side_pixels_(desired_image_side_pixels) {}
 
   void Start() {
     profile_image_downloader_.reset(new ProfileDownloader(this));
@@ -70,7 +68,7 @@
 
   std::string GetCachedPictureURL() const override { return std::string(); }
 
-  bool IsPreSignin() const override { return is_pre_signin_; }
+  bool IsPreSignin() const override { return true; }
 
   void OnProfileDownloadSuccess(ProfileDownloader* downloader) override {
     base::string16 full_name = downloader->GetProfileFullName();
@@ -108,11 +106,6 @@
   // Desired side length of the profile image (in pixels).
   const int desired_image_side_pixels_;
 
-  // True when the profile download is happening before the user has signed in,
-  // such as during first run when we can still get tokens and want to fetch
-  // the profile name and picture to display.
-  bool is_pre_signin_;
-
   DISALLOW_COPY_AND_ASSIGN(AccountInfoRetriever);
 };
 
@@ -123,8 +116,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& jprofile,
     const JavaParamRef<jstring>& jemail,
-    jint image_side_pixels,
-    jboolean is_pre_signin) {
+    jint image_side_pixels) {
   Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
   const std::string email = base::android::ConvertJavaStringToUTF8(env, jemail);
 
@@ -139,8 +131,7 @@
     return;
   }
 
-  AccountInfoRetriever* retriever =
-      new AccountInfoRetriever(profile, maybe_account_info.value().account_id,
-                               email, image_side_pixels, is_pre_signin);
+  AccountInfoRetriever* retriever = new AccountInfoRetriever(
+      profile, maybe_account_info.value().account_id, email, image_side_pixels);
   retriever->Start();
 }
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index c7bc4a7e..802afd5 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -456,11 +456,6 @@
 
   registry->RegisterBooleanPref(prefs::kForceEphemeralProfiles, false);
   registry->RegisterBooleanPref(prefs::kEnableMediaRouter, true);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  registry->RegisterBooleanPref(
-      prefs::kOobeMarketingOptInScreenFinished, false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #if !defined(OS_ANDROID)
   registry->RegisterBooleanPref(prefs::kShowCastIconInToolbar, false);
 #endif  // !defined(OS_ANDROID)
diff --git a/chrome/browser/profiles/profile_keep_alive_types.cc b/chrome/browser/profiles/profile_keep_alive_types.cc
index 3e314ae..d36a307d 100644
--- a/chrome/browser/profiles/profile_keep_alive_types.cc
+++ b/chrome/browser/profiles/profile_keep_alive_types.cc
@@ -17,6 +17,8 @@
       return out << "kBackgroundMode";
     case ProfileKeepAliveOrigin::kOffTheRecordProfile:
       return out << "kOffTheRecordProfile";
+    case ProfileKeepAliveOrigin::kDownloadInProgress:
+      return out << "kDownloadInProgress";
   }
   NOTREACHED();
   return out << static_cast<int>(origin);
diff --git a/chrome/browser/profiles/profile_keep_alive_types.h b/chrome/browser/profiles/profile_keep_alive_types.h
index 1979c14..c256d4c 100644
--- a/chrome/browser/profiles/profile_keep_alive_types.h
+++ b/chrome/browser/profiles/profile_keep_alive_types.h
@@ -31,7 +31,10 @@
   // A child off-the-record profile holds a strong reference to its parent.
   kOffTheRecordProfile = 3,
 
-  kMaxValue = kOffTheRecordProfile,
+  // This Profile is downloading a file.
+  kDownloadInProgress = 4,
+
+  kMaxValue = kDownloadInProgress,
 };
 
 std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 12bf3d9..a84c0c8 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -1282,6 +1282,14 @@
                                 Profile::CREATE_MODE_ASYNCHRONOUS);
 }
 
+bool ProfileManager::HasKeepAliveForTesting(const Profile* profile,
+                                            ProfileKeepAliveOrigin origin) {
+  DCHECK(profile);
+  ProfileInfo* info = GetProfileInfoByPath(profile->GetPath());
+  DCHECK(info);
+  return info->keep_alives[origin] > 0;
+}
+
 void ProfileManager::AddKeepAlive(const Profile* profile,
                                   ProfileKeepAliveOrigin origin) {
   DCHECK_NE(ProfileKeepAliveOrigin::kWaitingForFirstBrowserWindow, origin);
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index 811fe2d..1be24b4 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -268,6 +268,11 @@
                         bool success,
                         bool is_new_profile) override;
 
+  // Used for testing. Returns true if |profile| has at least one ref of type
+  // |origin|.
+  bool HasKeepAliveForTesting(const Profile* profile,
+                              ProfileKeepAliveOrigin origin);
+
  protected:
   // Creates a new profile by calling into the profile's profile creation
   // method. Virtual so that unittests can return a TestingProfile instead
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
index 185cb16..c9de2b8f 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -26,9 +26,13 @@
   "../common/automation_predicate.js",
   "../common/automation_util.js",
   "../common/constants.js",
+  "../common/cursors/cursor.js",
+  "../common/cursors/range.js",
+  "../common/cursors/recovery_strategy.js",
   "../common/event_generator.js",
   "../common/key_code.js",
   "../common/instance_checker.js",
+  "../common/string_util.js",
   "../common/tree_walker.js",
   "background/annotation/node_identifier.js",
   "background/annotation/user_annotation_handler.js",
@@ -43,7 +47,6 @@
   "background/classic_background.js",
   "background/color.js",
   "background/command_handler.js",
-  "background/cursors.js",
   "background/custom_automation_event.js",
   "background/desktop_automation_handler.js",
   "background/download_handler.js",
@@ -77,7 +80,6 @@
   "background/phonetic_data.js",
   "background/prefs.js",
   "background/range_automation_handler.js",
-  "background/recovery_strategy.js",
   "background/smart_sticky_mode.js",
   "background/tabs_api_handler.js",
   "background/user_action_monitor.js",
@@ -109,7 +111,6 @@
   "common/msgs.js",
   "common/nav_description.js",
   "common/spannable.js",
-  "common/string_util.js",
   "common/tts_background.js",
   "common/tts_base.js",
   "common/tts_interface.js",
@@ -450,7 +451,6 @@
       "background/background_test.js",
       "background/braille_command_data_test.js",
       "background/color_test.js",
-      "background/cursors_test.js",
       "background/download_handler_test.js",
       "background/editing/editing_test.js",
       "background/editing/intent_handler_test.js",
@@ -460,7 +460,6 @@
       "background/logging/log_store_test.js",
       "background/output_test.js",
       "background/portals_test.js",
-      "background/recovery_strategy_test.js",
       "background/settings_test.js",
       "background/smart_sticky_mode_test.js",
       "background/user_action_monitor_test.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/recovery_strategy_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/recovery_strategy_test.js
deleted file mode 100644
index e4e98dff..0000000
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/recovery_strategy_test.js
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2017 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 test fixture.
-GEN_INCLUDE([
-  '//chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js',
-]);
-
-/**
- * Test fixture for recovery strategy tests.
- */
-ChromeVoxRecoveryStrategyTest = class extends ChromeVoxNextE2ETest {
-  constructor() {
-    super();
-  }
-};
-
-
-TEST_F('ChromeVoxRecoveryStrategyTest', 'ReparentedRecovery', function() {
-  this.runWithLoadedTree(
-      `
-    <input type="text"></input>
-    <p id="p">hi</p>
-    <button id="go"</button>
-    <script>
-      document.getElementById('go').addEventListener('click', function() {
-        let p = document.getElementById('p');
-        p.remove();
-        document.body.appendChild(p);
-      });
-    </script>
-  `,
-      function(root) {
-        const p = root.find({role: RoleType.PARAGRAPH});
-        const s = root.find({role: RoleType.STATIC_TEXT});
-        const b = root.find({role: RoleType.BUTTON});
-        const bAncestryRecovery = new AncestryRecoveryStrategy(b);
-        const pAncestryRecovery = new AncestryRecoveryStrategy(p);
-        const sAncestryRecovery = new AncestryRecoveryStrategy(s);
-        const bTreePathRecovery = new TreePathRecoveryStrategy(b);
-        const pTreePathRecovery = new TreePathRecoveryStrategy(p);
-        const sTreePathRecovery = new TreePathRecoveryStrategy(s);
-        this.listenOnce(b, 'clicked', function() {
-          assertFalse(
-              bAncestryRecovery.requiresRecovery(),
-              'bAncestryRecovery.requiresRecovery');
-          assertTrue(
-              pAncestryRecovery.requiresRecovery(),
-              'pAncestryRecovery.requiresRecovery()');
-          assertTrue(
-              sAncestryRecovery.requiresRecovery(),
-              'sAncestryRecovery.requiresRecovery()');
-          assertFalse(
-              bTreePathRecovery.requiresRecovery(),
-              'bTreePathRecovery.requiresRecovery()');
-          assertTrue(
-              pTreePathRecovery.requiresRecovery(),
-              'pTreePathRecovery.requiresRecovery()');
-          assertTrue(
-              sTreePathRecovery.requiresRecovery(),
-              'sTreePathRecovery.requiresRecovery()');
-
-          assertEquals(RoleType.BUTTON, bAncestryRecovery.node.role);
-          assertEquals(root, pAncestryRecovery.node);
-          assertEquals(root, sAncestryRecovery.node);
-
-          assertEquals(b, bTreePathRecovery.node);
-          assertEquals(b, pTreePathRecovery.node);
-          assertEquals(b, sTreePathRecovery.node);
-
-          assertFalse(
-              bAncestryRecovery.requiresRecovery(),
-              'bAncestryRecovery.requiresRecovery()');
-          assertFalse(
-              pAncestryRecovery.requiresRecovery(),
-              'pAncestryRecovery.requiresRecovery()');
-          assertFalse(
-              sAncestryRecovery.requiresRecovery(),
-              'sAncestryRecovery.requiresRecovery()');
-          assertFalse(
-              bTreePathRecovery.requiresRecovery(),
-              'bTreePathRecovery.requiresRecovery()');
-          assertFalse(
-              pTreePathRecovery.requiresRecovery(),
-              'pTreePathRecovery.requiresRecovery()');
-          assertFalse(
-              sTreePathRecovery.requiresRecovery(),
-              'sTreePathRecovery.requiresRecovery()');
-        });
-        // Trigger the change.
-        b.doDefault();
-      });
-});
diff --git a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
index e10927d4..bf004bb 100644
--- a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
@@ -30,6 +30,9 @@
     "automation_util.js",
     "closure_shim.js",
     "constants.js",
+    "cursors/cursor.js",
+    "cursors/range.js",
+    "cursors/recovery_strategy.js",
     "event_generator.js",
     "event_handler.js",
     "gdocs_script.js",
@@ -38,6 +41,7 @@
     "rect_util.js",
     "repeated_event_handler.js",
     "repeated_tree_change_handler.js",
+    "string_util.js",
     "tree_walker.js",
   ]
   rewrite_rules = [ rebase_path(".", root_build_dir) + ":" ]
@@ -145,6 +149,8 @@
   sources = [
     "array_util_test.js",
     "automation_util_test.js",
+    "cursors/cursors_test.js",
+    "cursors/recovery_strategy_test.js",
     "event_generator_test.js",
     "repeated_event_handler_test.js",
     "repeated_tree_change_handler_test.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/cursors.js b/chrome/browser/resources/chromeos/accessibility/common/cursors/cursor.js
similarity index 74%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/background/cursors.js
rename to chrome/browser/resources/chromeos/accessibility/common/cursors/cursor.js
index bcf3680..0a31ee60 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/cursors.js
+++ b/chrome/browser/resources/chromeos/accessibility/common/cursors/cursor.js
@@ -3,13 +3,12 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Classes related to cursors that point to and select parts of
+ * @fileoverview Structures related to cursors that point to and select parts of
  * the automation tree.
  */
 
 goog.provide('cursors.Cursor');
 goog.provide('cursors.Movement');
-goog.provide('cursors.Range');
 goog.provide('cursors.Unit');
 
 goog.require('AncestryRecoveryStrategy');
@@ -699,274 +698,4 @@
     return new cursors.WrappingCursor(result.node, result.index);
   }
 };
-
-
-/**
- * Represents a range in the automation tree. There is no visible selection on
- * the page caused by usage of this object.
- * It is assumed that the caller provides |start| and |end| in document order.
- */
-cursors.Range = class {
-  /**
-   * @param {!cursors.Cursor} start
-   * @param {!cursors.Cursor} end
-   */
-  constructor(start, end) {
-    /** @type {!cursors.Cursor} @private */
-    this.start_ = start;
-    /** @type {!cursors.Cursor} @private */
-    this.end_ = end;
-  }
-
-  /**
-   * Convenience method to construct a Range surrounding one node.
-   * @param {!AutomationNode} node
-   * @return {!cursors.Range}
-   */
-  static fromNode(node) {
-    const cursor = cursors.WrappingCursor.fromNode(node);
-    return new cursors.Range(cursor, cursor);
-  }
-
-  /**
-   * Given |rangeA| and |rangeB| in order, determine which |Dir|
-   * relates them.
-   * @param {!cursors.Range} rangeA
-   * @param {!cursors.Range} rangeB
-   * @return {Dir}
-   */
-  static getDirection(rangeA, rangeB) {
-    if (!rangeA || !rangeB) {
-      return Dir.FORWARD;
-    }
-
-    if (!rangeA.start.node || !rangeA.end.node || !rangeB.start.node ||
-        !rangeB.end.node) {
-      return Dir.FORWARD;
-    }
-
-    // They are the same range.
-    if (rangeA.start.node === rangeB.start.node &&
-        rangeB.end.node === rangeA.end.node) {
-      return Dir.FORWARD;
-    }
-
-    const testDirA =
-        AutomationUtil.getDirection(rangeA.start.node, rangeB.end.node);
-    const testDirB =
-        AutomationUtil.getDirection(rangeB.start.node, rangeA.end.node);
-
-    // The two ranges are either partly overlapping or non overlapping.
-    if (testDirA === Dir.FORWARD && testDirB === Dir.BACKWARD) {
-      return Dir.FORWARD;
-    } else if (testDirA === Dir.BACKWARD && testDirB === Dir.FORWARD) {
-      return Dir.BACKWARD;
-    } else {
-      return testDirA;
-    }
-  }
-
-  /**
-   * Returns true if |rhs| is equal to this range.
-   * Use this for strict equality between ranges.
-   * @param {!cursors.Range} rhs
-   * @return {boolean}
-   */
-  equals(rhs) {
-    return this.start_.equals(rhs.start) && this.end_.equals(rhs.end);
-  }
-
-  equalsWithoutRecovery(rhs) {
-    return this.start_.equalsWithoutRecovery(rhs.start) &&
-        this.end_.equalsWithoutRecovery(rhs.end);
-  }
-
-  /**
-   * Returns true if |rhs| is equal to this range.
-   * Use this for loose equality between ranges.
-   * @param {!cursors.Range} rhs
-   * @return {boolean}
-   */
-  contentEquals(rhs) {
-    return this.start_.contentEquals(rhs.start) &&
-        this.end_.contentEquals(rhs.end);
-  }
-
-  /**
-   * Gets the directed end cursor of this range.
-   * @param {Dir} dir Which endpoint cursor to return;
-   *     Dir.FORWARD for end,
-   * Dir.BACKWARD for start.
-   * @return {!cursors.Cursor}
-   */
-  getBound(dir) {
-    return dir === Dir.FORWARD ? this.end_ : this.start_;
-  }
-
-  /**
-   * @return {!cursors.Cursor}
-   */
-  get start() {
-    return this.start_;
-  }
-
-  /**
-   * @return {!cursors.Cursor}
-   */
-  get end() {
-    return this.end_;
-  }
-
-  /**
-   * Returns true if this range covers less than a node.
-   * @return {boolean}
-   */
-  isSubNode() {
-    const startIndex = this.start.index;
-    const endIndex = this.end.index;
-    return this.start.node === this.end.node && startIndex !== -1 &&
-        endIndex !== -1 && startIndex !== endIndex &&
-        (startIndex !== 0 || endIndex !== this.start.getText().length);
-  }
-
-  /**
-   * Returns true if this range covers inline text (i.e. each end points to an
-   * inlineTextBox).
-   * @return {boolean?}
-   */
-  isInlineText() {
-    return this.start.node && this.end.node &&
-        this.start.node.role === this.end.node.role &&
-        this.start.node.role === RoleType.INLINE_TEXT_BOX;
-  }
-
-  /**
-   * Makes a Range which has been moved from this range by the given unit and
-   * direction.
-   * @param {cursors.Unit} unit
-   * @param {Dir} dir
-   * @return {cursors.Range}
-   */
-  move(unit, dir) {
-    let newStart = this.start_;
-    if (!newStart.node) {
-      return this;
-    }
-
-    let newEnd;
-    switch (unit) {
-      case cursors.Unit.CHARACTER:
-        newStart = newStart.move(unit, cursors.Movement.DIRECTIONAL, dir);
-        newEnd = newStart.move(unit, cursors.Movement.DIRECTIONAL, Dir.FORWARD);
-        // Character crossed a node; collapses to the end of the node.
-        if (newStart.node !== newEnd.node) {
-          newEnd = new cursors.Cursor(newStart.node, newStart.index + 1);
-        }
-        break;
-      case cursors.Unit.WORD:
-      case cursors.Unit.LINE:
-        newStart = newStart.move(unit, cursors.Movement.DIRECTIONAL, dir);
-        newStart = newStart.move(unit, cursors.Movement.BOUND, Dir.BACKWARD);
-        newEnd = newStart.move(unit, cursors.Movement.BOUND, Dir.FORWARD);
-        break;
-      case cursors.Unit.NODE:
-        newStart = newStart.move(unit, cursors.Movement.DIRECTIONAL, dir);
-        newEnd = newStart;
-        break;
-      default:
-        throw Error('Invalid unit: ' + unit);
-    }
-    return new cursors.Range(newStart, newEnd);
-  }
-
-  /**
-   * Select the text contained within this range.
-   */
-  select() {
-    let start = this.start_, end = this.end_;
-    if (this.start.compare(this.end) === Dir.BACKWARD) {
-      start = this.end;
-      end = this.start;
-    }
-    const startNode = start.selectionNode_;
-    const endNode = end.selectionNode_;
-
-    if (!startNode || !endNode) {
-      return;
-    }
-
-    // Only allow selections within the same web tree.
-    if (startNode.root && startNode.root.role === RoleType.ROOT_WEB_AREA &&
-        startNode.root === endNode.root) {
-      // We want to adjust to select the entire node for node offsets;
-      // otherwise, use the plain character offset.
-      const startIndex = start.selectionIndex_;
-      let endIndex = end.index_ === cursors.NODE_INDEX ?
-          end.selectionIndex_ + 1 :
-          end.selectionIndex_;
-
-      // Richly editables should always set a caret, but not select. This
-      // makes it possible to navigate through content editables using
-      // ChromeVox keys and not hear selections as you go.
-      if (startNode.state[StateType.RICHLY_EDITABLE] ||
-          endNode.state[StateType.RICHLY_EDITABLE]) {
-        endIndex = startIndex;
-      }
-
-      chrome.automation.setDocumentSelection({
-        anchorObject: startNode,
-        anchorOffset: startIndex,
-        focusObject: endNode,
-        focusOffset: endIndex
-      });
-    }
-  }
-
-  /**
-   * Returns true if this range has either cursor end on web content.
-   * @return {boolean}
-   */
-  isWebRange() {
-    return this.isValid() &&
-        (this.start.node.root.role !== RoleType.DESKTOP ||
-         this.end.node.root.role !== RoleType.DESKTOP);
-  }
-
-  /**
-   * Returns whether this range has valid start and end cursors.
-   * @return {boolean}
-   */
-  isValid() {
-    return this.start.isValid() && this.end.isValid();
-  }
-
-  /**
-   * Compares this range with |rhs|.
-   * @param {cursors.Range} rhs
-   * @return {Dir|undefined} Dir.BACKWARD if |rhs| comes
-   *     before this range in
-   * document order. Dir.FORWARD if |rhs| comes after this range.
-   * Undefined otherwise.
-   */
-  compare(rhs) {
-    const startDir = this.start.compare(rhs.start);
-    const endDir = this.end.compare(rhs.end);
-    if (startDir !== endDir) {
-      return undefined;
-    }
-
-    return startDir;
-  }
-
-  /**
-   * Returns an undirected version of this range.
-   * @return {!cursors.Range}
-   */
-  normalize() {
-    if (this.start.compare(this.end) === Dir.BACKWARD) {
-      return new cursors.Range(this.end, this.start);
-    }
-    return this;
-  }
-};
 });  // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/cursors_test.js b/chrome/browser/resources/chromeos/accessibility/common/cursors/cursors_test.js
similarity index 65%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/background/cursors_test.js
rename to chrome/browser/resources/chromeos/accessibility/common/cursors/cursors_test.js
index 1bb4c31..e00a5775 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/cursors_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/common/cursors/cursors_test.js
@@ -10,7 +10,7 @@
 /**
  * Test fixture for cursors.
  */
-ChromeVoxCursorsTest = class extends ChromeVoxNextE2ETest {
+AccessibilityExtensionCursorsTest = class extends ChromeVoxNextE2ETest {
   /** Test cursors.Cursor. @const {string} */
   get CURSOR() {
     return 'cursor';
@@ -53,93 +53,93 @@
       const expected = move[3];
       this.makeCursorAssertion(expected, cursor);
     }
+  }
+
+  /**
+   * Performs a series of operations on a range and asserts the result.
+   * @param {cursors.Range} range The starting range.
+   * @param {!Array<Array<
+   *          cursors.Unit|
+   *          cursors.Movement|
+   *          constants.Dir|
+   *          Object>>}
+   *     moves An array of arrays. Each inner array contains 4 items: unit,
+   *     direction, start and end assertions objects. See example below.
+   */
+  rangeMoveAndAssert(range, moves) {
+    let move = null;
+    while (move = moves.shift()) {
+      range = range.move(move[0], move[1]);
+      const expectedStart = move[2];
+      const expectedEnd = move[3];
+
+      this.makeCursorAssertion(expectedStart, range.start);
+      this.makeCursorAssertion(expectedEnd, range.end);
     }
+  }
 
-    /**
-     * Performs a series of operations on a range and asserts the result.
-     * @param {cursors.Range} range The starting range.
-     * @param {!Array<Array<
-     *          cursors.Unit|
-     *          cursors.Movement|
-     *          constants.Dir|
-     *          Object>>}
-     *     moves An array of arrays. Each inner array contains 4 items: unit,
-     *     direction, start and end assertions objects. See example below.
-     */
-    rangeMoveAndAssert(range, moves) {
-      let move = null;
-      while (move = moves.shift()) {
-        range = range.move(move[0], move[1]);
-        const expectedStart = move[2];
-        const expectedEnd = move[3];
-
-        this.makeCursorAssertion(expectedStart, range.start);
-        this.makeCursorAssertion(expectedEnd, range.end);
-      }
+  /**
+   * Makes assertions about the given |cursor|.
+   * @param {Object} expected
+   * @param {Cursor} cursor
+   */
+  makeCursorAssertion(expected, cursor) {
+    if (goog.isDef(expected.value)) {
+      assertEquals(expected.value, cursor.node.name);
     }
-
-    /**
-     * Makes assertions about the given |cursor|.
-     * @param {Object} expected
-     * @param {Cursor} cursor
-     */
-    makeCursorAssertion(expected, cursor) {
-      if (goog.isDef(expected.value)) {
-        assertEquals(expected.value, cursor.node.name);
-      }
-      if (goog.isDef(expected.index)) {
-        assertEquals(expected.index, cursor.index);
-      }
+    if (goog.isDef(expected.index)) {
+      assertEquals(expected.index, cursor.index);
     }
+  }
 
-    /**
-     * Runs the specified moves on the |doc| and asserts expectations.
-     * @param {function} doc
-     * @param {string=} opt_testType Either CURSOR or RANGE.
-     */
-    runCursorMovesOnDocument(doc, moves, opt_testType) {
-      this.runWithLoadedTree(doc, function(root) {
-        let start = null;
+  /**
+   * Runs the specified moves on the |doc| and asserts expectations.
+   * @param {function} doc
+   * @param {string=} opt_testType Either CURSOR or RANGE.
+   */
+  runCursorMovesOnDocument(doc, moves, opt_testType) {
+    this.runWithLoadedTree(doc, function(root) {
+      let start = null;
 
-        // This occurs as a result of a load complete.
-        start = AutomationUtil.findNodePost(
-            root, FORWARD, AutomationPredicate.leaf);
+      // This occurs as a result of a load complete.
+      start =
+          AutomationUtil.findNodePost(root, FORWARD, AutomationPredicate.leaf);
 
+      const cursor = new cursors.Cursor(start, 0);
+      if (!opt_testType || opt_testType === this.CURSOR) {
         const cursor = new cursors.Cursor(start, 0);
-        if (!opt_testType || opt_testType === this.CURSOR) {
-          const cursor = new cursors.Cursor(start, 0);
-          this.cursorMoveAndAssert(cursor, moves);
-        } else if (opt_testType === this.RANGE) {
-          const range = new cursors.Range(cursor, cursor);
-          this.rangeMoveAndAssert(range, moves);
-        }
-      });
-    }
+        this.cursorMoveAndAssert(cursor, moves);
+      } else if (opt_testType === this.RANGE) {
+        const range = new cursors.Range(cursor, cursor);
+        this.rangeMoveAndAssert(range, moves);
+      }
+    });
+  }
 
-    get simpleDoc() {
-      return `
+  get simpleDoc() {
+    return `
       <p>start <span>same line</span>
       <p>end
     `;
-    }
+  }
 
-    get multiInlineDoc() {
-      return `
+  get multiInlineDoc() {
+    return `
       <p style='max-width: 5px'>start diff line</p>
       <p>end
     `;
-    }
+  }
 
-    get buttonAndInlineTextDoc() {
-      return `
+  get buttonAndInlineTextDoc() {
+    return `
       <div>Inline text content</div>
       <div role="button">Button example content</div>
     `;
-    }
+  }
 };
 
 
-TEST_F('ChromeVoxCursorsTest', 'CharacterCursor', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'CharacterCursor', function() {
   this.runCursorMovesOnDocument(this.simpleDoc, [
     [CHARACTER, DIRECTIONAL, FORWARD, {index: 1, value: 'start '}],
     [CHARACTER, DIRECTIONAL, BACKWARD, {index: 0, value: 'start '}],
@@ -160,7 +160,7 @@
   ]);
 });
 
-TEST_F('ChromeVoxCursorsTest', 'WordCursor', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'WordCursor', function() {
   this.runCursorMovesOnDocument(this.simpleDoc, [
     // Word (BOUND).
     [WORD, BOUND, BACKWARD, {index: 0, value: 'start '}],
@@ -183,7 +183,7 @@
   ]);
 });
 
-TEST_F('ChromeVoxCursorsTest', 'CharacterWordCursor', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'CharacterWordCursor', function() {
   this.runCursorMovesOnDocument(this.simpleDoc, [
     [CHARACTER, DIRECTIONAL, FORWARD, {index: 1, value: 'start '}],
 
@@ -200,7 +200,7 @@
   ]);
 });
 
-TEST_F('ChromeVoxCursorsTest', 'LineCursor', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'LineCursor', function() {
   this.runCursorMovesOnDocument(this.simpleDoc, [
     // Line (BOUND).
     [LINE, BOUND, FORWARD, {value: 'same line'}],
@@ -218,7 +218,7 @@
   ]);
 });
 
-TEST_F('ChromeVoxCursorsTest', 'CharacterRange', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'CharacterRange', function() {
   this.runCursorMovesOnDocument(
       this.simpleDoc,
       [
@@ -280,7 +280,7 @@
       this.RANGE);
 });
 
-TEST_F('ChromeVoxCursorsTest', 'WordRange', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'WordRange', function() {
   this.runCursorMovesOnDocument(
       this.simpleDoc,
       [
@@ -318,7 +318,7 @@
 });
 
 
-TEST_F('ChromeVoxCursorsTest', 'LineRange', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'LineRange', function() {
   this.runCursorMovesOnDocument(
       this.simpleDoc,
       [
@@ -340,27 +340,29 @@
       this.RANGE);
 });
 
-TEST_F('ChromeVoxCursorsTest', 'DontSplitOnNodeNavigation', function() {
-  this.runWithLoadedTree(this.multiInlineDoc, function(root) {
-    const para = root.firstChild;
-    assertEquals('paragraph', para.role);
-    let cursor = new cursors.Cursor(para.firstChild, 0);
-    cursor = cursor.move(NODE, DIRECTIONAL, FORWARD);
-    assertEquals('staticText', cursor.node.role);
-    assertEquals('end', cursor.node.name);
+TEST_F(
+    'AccessibilityExtensionCursorsTest', 'DontSplitOnNodeNavigation',
+    function() {
+      this.runWithLoadedTree(this.multiInlineDoc, function(root) {
+        const para = root.firstChild;
+        assertEquals('paragraph', para.role);
+        let cursor = new cursors.Cursor(para.firstChild, 0);
+        cursor = cursor.move(NODE, DIRECTIONAL, FORWARD);
+        assertEquals('staticText', cursor.node.role);
+        assertEquals('end', cursor.node.name);
 
-    cursor = cursor.move(NODE, DIRECTIONAL, BACKWARD);
-    assertEquals('staticText', cursor.node.role);
-    assertEquals('start diff line', cursor.node.name);
+        cursor = cursor.move(NODE, DIRECTIONAL, BACKWARD);
+        assertEquals('staticText', cursor.node.role);
+        assertEquals('start diff line', cursor.node.name);
 
-    assertEquals('inlineTextBox', cursor.node.firstChild.role);
-    assertEquals('start ', cursor.node.firstChild.name);
-    assertEquals('diff ', cursor.node.firstChild.nextSibling.name);
-    assertEquals('line', cursor.node.lastChild.name);
-  });
-});
+        assertEquals('inlineTextBox', cursor.node.firstChild.role);
+        assertEquals('start ', cursor.node.firstChild.name);
+        assertEquals('diff ', cursor.node.firstChild.nextSibling.name);
+        assertEquals('line', cursor.node.lastChild.name);
+      });
+    });
 
-TEST_F('ChromeVoxCursorsTest', 'WrappingCursors', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'WrappingCursors', function() {
   this.runWithLoadedTree(this.multiInlineDoc, function(root) {
     const first = root;
     const last = root.lastChild.firstChild;
@@ -376,7 +378,7 @@
   });
 });
 
-TEST_F('ChromeVoxCursorsTest', 'IsInWebRange', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'IsInWebRange', function() {
   this.runWithLoadedTree(this.simpleDoc, function(root) {
     const para = root.firstChild;
     const webRange = cursors.Range.fromNode(para);
@@ -386,7 +388,7 @@
   });
 });
 
-TEST_F('ChromeVoxCursorsTest', 'SingleDocSelection', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'SingleDocSelection', function() {
   this.runWithLoadedTree(
       `
     <span>start</span>
@@ -430,35 +432,38 @@
       });
 });
 
-TEST_F('ChromeVoxCursorsTest', 'MultiLineOffsetSelection', function() {
-  this.runWithLoadedTree(this.multiInlineDoc, function(root) {
-    const secondLine = root.firstChild.firstChild.firstChild.nextSibling;
-    assertEquals('inlineTextBox', secondLine.role);
-    assertEquals('diff ', secondLine.name);
+TEST_F(
+    'AccessibilityExtensionCursorsTest', 'MultiLineOffsetSelection',
+    function() {
+      this.runWithLoadedTree(this.multiInlineDoc, function(root) {
+        const secondLine = root.firstChild.firstChild.firstChild.nextSibling;
+        assertEquals('inlineTextBox', secondLine.role);
+        assertEquals('diff ', secondLine.name);
 
-    let secondLineCursor = new cursors.Cursor(secondLine, -1);
-    // The selected node moves to the static text node.
-    assertEquals(secondLineCursor.node.parent, secondLineCursor.selectionNode_);
+        let secondLineCursor = new cursors.Cursor(secondLine, -1);
+        // The selected node moves to the static text node.
+        assertEquals(
+            secondLineCursor.node.parent, secondLineCursor.selectionNode_);
 
-    // This selects the entire node via a character offset.
-    assertEquals(6, secondLineCursor.selectionIndex_);
+        // This selects the entire node via a character offset.
+        assertEquals(6, secondLineCursor.selectionIndex_);
 
-    // Index into the characters.
-    secondLineCursor = new cursors.Cursor(secondLine, 1);
-    assertEquals(7, secondLineCursor.selectionIndex_);
+        // Index into the characters.
+        secondLineCursor = new cursors.Cursor(secondLine, 1);
+        assertEquals(7, secondLineCursor.selectionIndex_);
 
-    // Now, try selecting via node offsets.
-    let cursor = new cursors.Cursor(root.firstChild, -1);
-    assertEquals(root, cursor.selectionNode_);
-    assertEquals(0, cursor.selectionIndex_);
+        // Now, try selecting via node offsets.
+        let cursor = new cursors.Cursor(root.firstChild, -1);
+        assertEquals(root, cursor.selectionNode_);
+        assertEquals(0, cursor.selectionIndex_);
 
-    cursor = new cursors.Cursor(root.firstChild.nextSibling, -1);
-    assertEquals(root, cursor.selectionNode_);
-    assertEquals(1, cursor.selectionIndex_);
-  });
-});
+        cursor = new cursors.Cursor(root.firstChild.nextSibling, -1);
+        assertEquals(root, cursor.selectionNode_);
+        assertEquals(1, cursor.selectionIndex_);
+      });
+    });
 
-TEST_F('ChromeVoxCursorsTest', 'InlineElementOffset', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'InlineElementOffset', function() {
   this.runWithLoadedTree(
       `
     <span>start</span>
@@ -501,7 +506,7 @@
       });
 });
 
-TEST_F('ChromeVoxCursorsTest', 'ContentEquality', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'ContentEquality', function() {
   this.runWithLoadedTree(
       `
     <div role="region">this is a test</button>
@@ -535,7 +540,7 @@
       });
 });
 
-TEST_F('ChromeVoxCursorsTest', 'DeepEquivalency', function() {
+TEST_F('AccessibilityExtensionCursorsTest', 'DeepEquivalency', function() {
   this.runWithLoadedTree(
       `
     <p style="word-spacing:100000px">this is a test</p>
@@ -588,107 +593,115 @@
       });
 });
 
-TEST_F('ChromeVoxCursorsTest', 'DeepEquivalencyBeyondLastChild', function() {
-  this.runWithLoadedTree(
-      `
+TEST_F(
+    'AccessibilityExtensionCursorsTest', 'DeepEquivalencyBeyondLastChild',
+    function() {
+      this.runWithLoadedTree(
+          `
     <p>test</p>
   `,
-      function(root) {
-        const paragraph = root.find({role: RoleType.PARAGRAPH});
-        assertEquals(1, paragraph.children.length);
-        const cursor = new cursors.Cursor(paragraph, 1);
+          function(root) {
+            const paragraph = root.find({role: RoleType.PARAGRAPH});
+            assertEquals(1, paragraph.children.length);
+            const cursor = new cursors.Cursor(paragraph, 1);
 
-        const deep = cursor.deepEquivalent;
-        assertEquals(RoleType.STATIC_TEXT, deep.node.role);
-        assertEquals(4, deep.index);
-      });
-});
+            const deep = cursor.deepEquivalent;
+            assertEquals(RoleType.STATIC_TEXT, deep.node.role);
+            assertEquals(4, deep.index);
+          });
+    });
 
-TEST_F('ChromeVoxCursorsTest', 'SelectionAdjustmentsRichText', function() {
-  this.runWithLoadedTree(
-      `
+TEST_F(
+    'AccessibilityExtensionCursorsTest', 'SelectionAdjustmentsRichText',
+    function() {
+      this.runWithLoadedTree(
+          `
     <div contenteditable><p>test</p><p>123</p></div>
   `,
-      function(root) {
-        const textField = root.firstChild;
-        const paragraph = textField.firstChild;
-        const otherParagraph = textField.lastChild;
-        const staticText = paragraph.firstChild;
-        const otherStaticText = otherParagraph.firstChild;
+          function(root) {
+            const textField = root.firstChild;
+            const paragraph = textField.firstChild;
+            const otherParagraph = textField.lastChild;
+            const staticText = paragraph.firstChild;
+            const otherStaticText = otherParagraph.firstChild;
 
-        // Ranges by default surround a node. Ensure it results in a collapsed
-        // selection.
-        let range = cursors.Range.fromNode(staticText);
-        assertEquals(0, range.start.selectionIndex_);
-        assertEquals(0, range.end.selectionIndex_);
-        assertEquals(paragraph, range.start.selectionNode_);
-        assertEquals(paragraph, range.end.selectionNode_);
+            // Ranges by default surround a node. Ensure it results in a
+            // collapsed selection.
+            let range = cursors.Range.fromNode(staticText);
+            assertEquals(0, range.start.selectionIndex_);
+            assertEquals(0, range.end.selectionIndex_);
+            assertEquals(paragraph, range.start.selectionNode_);
+            assertEquals(paragraph, range.end.selectionNode_);
 
-        // Text selection.
-        range = new cursors.Range(
-            new cursors.Cursor(staticText, 2),
-            new cursors.Cursor(staticText, 4));
-        assertEquals(2, range.start.selectionIndex_);
-        assertEquals(4, range.end.selectionIndex_);
-        assertEquals(staticText, range.start.selectionNode_);
-        assertEquals(staticText, range.end.selectionNode_);
+            // Text selection.
+            range = new cursors.Range(
+                new cursors.Cursor(staticText, 2),
+                new cursors.Cursor(staticText, 4));
+            assertEquals(2, range.start.selectionIndex_);
+            assertEquals(4, range.end.selectionIndex_);
+            assertEquals(staticText, range.start.selectionNode_);
+            assertEquals(staticText, range.end.selectionNode_);
 
-        // Tree selection.
-        range = cursors.Range.fromNode(paragraph);
-        assertEquals(0, range.start.selectionIndex_);
-        assertEquals(0, range.end.selectionIndex_);
-        assertEquals(textField, range.start.selectionNode_);
-        assertEquals(textField, range.end.selectionNode_);
+            // Tree selection.
+            range = cursors.Range.fromNode(paragraph);
+            assertEquals(0, range.start.selectionIndex_);
+            assertEquals(0, range.end.selectionIndex_);
+            assertEquals(textField, range.start.selectionNode_);
+            assertEquals(textField, range.end.selectionNode_);
 
-        range = cursors.Range.fromNode(otherStaticText);
-        assertEquals(0, range.start.selectionIndex_);
-        assertEquals(0, range.end.selectionIndex_);
-        assertEquals(otherParagraph, range.start.selectionNode_);
-        assertEquals(otherParagraph, range.end.selectionNode_);
+            range = cursors.Range.fromNode(otherStaticText);
+            assertEquals(0, range.start.selectionIndex_);
+            assertEquals(0, range.end.selectionIndex_);
+            assertEquals(otherParagraph, range.start.selectionNode_);
+            assertEquals(otherParagraph, range.end.selectionNode_);
 
-        range = cursors.Range.fromNode(otherParagraph);
-        assertEquals(1, range.start.selectionIndex_);
-        assertEquals(1, range.end.selectionIndex_);
-        assertEquals(textField, range.start.selectionNode_);
-        assertEquals(textField, range.end.selectionNode_);
-      });
-});
+            range = cursors.Range.fromNode(otherParagraph);
+            assertEquals(1, range.start.selectionIndex_);
+            assertEquals(1, range.end.selectionIndex_);
+            assertEquals(textField, range.start.selectionNode_);
+            assertEquals(textField, range.end.selectionNode_);
+          });
+    });
 
-TEST_F('ChromeVoxCursorsTest', 'SelectionAdjustmentsNonRichText', function() {
-  this.runWithLoadedTree(
-      `
+TEST_F(
+    'AccessibilityExtensionCursorsTest', 'SelectionAdjustmentsNonRichText',
+    function() {
+      this.runWithLoadedTree(
+          `
     <input type="text"></input>
     <textarea></textarea>
   `,
-      function(root) {
-        const testEditable = function(edit) {
-          // Occurs as part of ordinary (non-text) navigation.
-          let range = cursors.Range.fromNode(edit);
-          assertEquals(-1, range.start.selectionIndex_);
-          assertEquals(-1, range.end.selectionIndex_);
-          assertEquals(edit, range.start.selectionNode_);
-          assertEquals(edit, range.end.selectionNode_);
+          function(root) {
+            const testEditable = function(edit) {
+              // Occurs as part of ordinary (non-text) navigation.
+              let range = cursors.Range.fromNode(edit);
+              assertEquals(-1, range.start.selectionIndex_);
+              assertEquals(-1, range.end.selectionIndex_);
+              assertEquals(edit, range.start.selectionNode_);
+              assertEquals(edit, range.end.selectionNode_);
 
-          // Occurs as a result of explicit text nav e.g. nextCharacter command.
-          range = new cursors.Range(
-              new cursors.Cursor(edit, 2), new cursors.Cursor(edit, 3));
-          assertEquals(2, range.start.selectionIndex_);
-          assertEquals(3, range.end.selectionIndex_);
-          assertEquals(edit, range.start.selectionNode_);
-          assertEquals(edit, range.end.selectionNode_);
-        };
+              // Occurs as a result of explicit text nav e.g. nextCharacter
+              // command.
+              range = new cursors.Range(
+                  new cursors.Cursor(edit, 2), new cursors.Cursor(edit, 3));
+              assertEquals(2, range.start.selectionIndex_);
+              assertEquals(3, range.end.selectionIndex_);
+              assertEquals(edit, range.start.selectionNode_);
+              assertEquals(edit, range.end.selectionNode_);
+            };
 
-        const textField = root.firstChild.firstChild;
-        const textArea = root.lastChild.lastChild;
+            const textField = root.firstChild.firstChild;
+            const textArea = root.lastChild.lastChild;
 
-        // Both of these should behave in the same way.
-        testEditable(textField);
-        testEditable(textArea);
-      });
-});
+            // Both of these should behave in the same way.
+            testEditable(textField);
+            testEditable(textArea);
+          });
+    });
 
 TEST_F(
-    'ChromeVoxCursorsTest', 'MovementByWordThroughNonInlineText', function() {
+    'AccessibilityExtensionCursorsTest', 'MovementByWordThroughNonInlineText',
+    function() {
       this.runCursorMovesOnDocument(this.buttonAndInlineTextDoc, [
         // Move forward by word.
         // 'text' start and end indices.
diff --git a/chrome/browser/resources/chromeos/accessibility/common/cursors/range.js b/chrome/browser/resources/chromeos/accessibility/common/cursors/range.js
new file mode 100644
index 0000000..7a7f01c
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/common/cursors/range.js
@@ -0,0 +1,291 @@
+// 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.
+
+/**
+ * @fileoverview Structures related to ranges, which are pairs of cursors over
+ * the automation tree.
+ */
+
+goog.provide('cursors.Range');
+
+goog.require('AutomationUtil');
+goog.require('constants');
+goog.require('cursors.Cursor');
+
+goog.scope(function() {
+const AutomationNode = chrome.automation.AutomationNode;
+const Dir = constants.Dir;
+const RoleType = chrome.automation.RoleType;
+const StateType = chrome.automation.StateType;
+
+
+/**
+ * Represents a range in the automation tree. There is no visible selection on
+ * the page caused by usage of this object.
+ * It is assumed that the caller provides |start| and |end| in document order.
+ */
+cursors.Range = class {
+  /**
+   * @param {!cursors.Cursor} start
+   * @param {!cursors.Cursor} end
+   */
+  constructor(start, end) {
+    /** @type {!cursors.Cursor} @private */
+    this.start_ = start;
+    /** @type {!cursors.Cursor} @private */
+    this.end_ = end;
+  }
+
+  /**
+   * Convenience method to construct a Range surrounding one node.
+   * @param {!AutomationNode} node
+   * @return {!cursors.Range}
+   */
+  static fromNode(node) {
+    const cursor = cursors.WrappingCursor.fromNode(node);
+    return new cursors.Range(cursor, cursor);
+  }
+
+  /**
+   * Given |rangeA| and |rangeB| in order, determine which |Dir|
+   * relates them.
+   * @param {!cursors.Range} rangeA
+   * @param {!cursors.Range} rangeB
+   * @return {Dir}
+   */
+  static getDirection(rangeA, rangeB) {
+    if (!rangeA || !rangeB) {
+      return Dir.FORWARD;
+    }
+
+    if (!rangeA.start.node || !rangeA.end.node || !rangeB.start.node ||
+        !rangeB.end.node) {
+      return Dir.FORWARD;
+    }
+
+    // They are the same range.
+    if (rangeA.start.node === rangeB.start.node &&
+        rangeB.end.node === rangeA.end.node) {
+      return Dir.FORWARD;
+    }
+
+    const testDirA =
+        AutomationUtil.getDirection(rangeA.start.node, rangeB.end.node);
+    const testDirB =
+        AutomationUtil.getDirection(rangeB.start.node, rangeA.end.node);
+
+    // The two ranges are either partly overlapping or non overlapping.
+    if (testDirA === Dir.FORWARD && testDirB === Dir.BACKWARD) {
+      return Dir.FORWARD;
+    } else if (testDirA === Dir.BACKWARD && testDirB === Dir.FORWARD) {
+      return Dir.BACKWARD;
+    } else {
+      return testDirA;
+    }
+  }
+
+  /**
+   * Returns true if |rhs| is equal to this range.
+   * Use this for strict equality between ranges.
+   * @param {!cursors.Range} rhs
+   * @return {boolean}
+   */
+  equals(rhs) {
+    return this.start_.equals(rhs.start) && this.end_.equals(rhs.end);
+  }
+
+  equalsWithoutRecovery(rhs) {
+    return this.start_.equalsWithoutRecovery(rhs.start) &&
+        this.end_.equalsWithoutRecovery(rhs.end);
+  }
+
+  /**
+   * Returns true if |rhs| is equal to this range.
+   * Use this for loose equality between ranges.
+   * @param {!cursors.Range} rhs
+   * @return {boolean}
+   */
+  contentEquals(rhs) {
+    return this.start_.contentEquals(rhs.start) &&
+        this.end_.contentEquals(rhs.end);
+  }
+
+  /**
+   * Gets the directed end cursor of this range.
+   * @param {Dir} dir Which endpoint cursor to return;
+   *     Dir.FORWARD for end,
+   * Dir.BACKWARD for start.
+   * @return {!cursors.Cursor}
+   */
+  getBound(dir) {
+    return dir === Dir.FORWARD ? this.end_ : this.start_;
+  }
+
+  /**
+   * @return {!cursors.Cursor}
+   */
+  get start() {
+    return this.start_;
+  }
+
+  /**
+   * @return {!cursors.Cursor}
+   */
+  get end() {
+    return this.end_;
+  }
+
+  /**
+   * Returns true if this range covers less than a node.
+   * @return {boolean}
+   */
+  isSubNode() {
+    const startIndex = this.start.index;
+    const endIndex = this.end.index;
+    return this.start.node === this.end.node && startIndex !== -1 &&
+        endIndex !== -1 && startIndex !== endIndex &&
+        (startIndex !== 0 || endIndex !== this.start.getText().length);
+  }
+
+  /**
+   * Returns true if this range covers inline text (i.e. each end points to an
+   * inlineTextBox).
+   * @return {boolean?}
+   */
+  isInlineText() {
+    return this.start.node && this.end.node &&
+        this.start.node.role === this.end.node.role &&
+        this.start.node.role === RoleType.INLINE_TEXT_BOX;
+  }
+
+  /**
+   * Makes a Range which has been moved from this range by the given unit and
+   * direction.
+   * @param {cursors.Unit} unit
+   * @param {Dir} dir
+   * @return {cursors.Range}
+   */
+  move(unit, dir) {
+    let newStart = this.start_;
+    if (!newStart.node) {
+      return this;
+    }
+
+    let newEnd;
+    switch (unit) {
+      case cursors.Unit.CHARACTER:
+        newStart = newStart.move(unit, cursors.Movement.DIRECTIONAL, dir);
+        newEnd = newStart.move(unit, cursors.Movement.DIRECTIONAL, Dir.FORWARD);
+        // Character crossed a node; collapses to the end of the node.
+        if (newStart.node !== newEnd.node) {
+          newEnd = new cursors.Cursor(newStart.node, newStart.index + 1);
+        }
+        break;
+      case cursors.Unit.WORD:
+      case cursors.Unit.LINE:
+        newStart = newStart.move(unit, cursors.Movement.DIRECTIONAL, dir);
+        newStart = newStart.move(unit, cursors.Movement.BOUND, Dir.BACKWARD);
+        newEnd = newStart.move(unit, cursors.Movement.BOUND, Dir.FORWARD);
+        break;
+      case cursors.Unit.NODE:
+        newStart = newStart.move(unit, cursors.Movement.DIRECTIONAL, dir);
+        newEnd = newStart;
+        break;
+      default:
+        throw Error('Invalid unit: ' + unit);
+    }
+    return new cursors.Range(newStart, newEnd);
+  }
+
+  /**
+   * Select the text contained within this range.
+   */
+  select() {
+    let start = this.start_, end = this.end_;
+    if (this.start.compare(this.end) === Dir.BACKWARD) {
+      start = this.end;
+      end = this.start;
+    }
+    const startNode = start.selectionNode_;
+    const endNode = end.selectionNode_;
+
+    if (!startNode || !endNode) {
+      return;
+    }
+
+    // Only allow selections within the same web tree.
+    if (startNode.root && startNode.root.role === RoleType.ROOT_WEB_AREA &&
+        startNode.root === endNode.root) {
+      // We want to adjust to select the entire node for node offsets;
+      // otherwise, use the plain character offset.
+      const startIndex = start.selectionIndex_;
+      let endIndex = end.index_ === cursors.NODE_INDEX ?
+          end.selectionIndex_ + 1 :
+          end.selectionIndex_;
+
+      // Richly editables should always set a caret, but not select. This
+      // makes it possible to navigate through content editables using
+      // ChromeVox keys and not hear selections as you go.
+      if (startNode.state[StateType.RICHLY_EDITABLE] ||
+          endNode.state[StateType.RICHLY_EDITABLE]) {
+        endIndex = startIndex;
+      }
+
+      chrome.automation.setDocumentSelection({
+        anchorObject: startNode,
+        anchorOffset: startIndex,
+        focusObject: endNode,
+        focusOffset: endIndex
+      });
+    }
+  }
+
+  /**
+   * Returns true if this range has either cursor end on web content.
+   * @return {boolean}
+   */
+  isWebRange() {
+    return this.isValid() &&
+        (this.start.node.root.role !== RoleType.DESKTOP ||
+         this.end.node.root.role !== RoleType.DESKTOP);
+  }
+
+  /**
+   * Returns whether this range has valid start and end cursors.
+   * @return {boolean}
+   */
+  isValid() {
+    return this.start.isValid() && this.end.isValid();
+  }
+
+  /**
+   * Compares this range with |rhs|.
+   * @param {cursors.Range} rhs
+   * @return {Dir|undefined} Dir.BACKWARD if |rhs| comes
+   *     before this range in
+   * document order. Dir.FORWARD if |rhs| comes after this range.
+   * Undefined otherwise.
+   */
+  compare(rhs) {
+    const startDir = this.start.compare(rhs.start);
+    const endDir = this.end.compare(rhs.end);
+    if (startDir !== endDir) {
+      return undefined;
+    }
+
+    return startDir;
+  }
+
+  /**
+   * Returns an undirected version of this range.
+   * @return {!cursors.Range}
+   */
+  normalize() {
+    if (this.start.compare(this.end) === Dir.BACKWARD) {
+      return new cursors.Range(this.end, this.start);
+    }
+    return this;
+  }
+};
+});  // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/recovery_strategy.js b/chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/background/recovery_strategy.js
rename to chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy.js
diff --git a/chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy_test.js b/chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy_test.js
new file mode 100644
index 0000000..bf648a7
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/common/cursors/recovery_strategy_test.js
@@ -0,0 +1,97 @@
+// Copyright 2017 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 test fixture.
+GEN_INCLUDE([
+  '//chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js',
+]);
+
+/**
+ * Test fixture for recovery strategy tests.
+ */
+AccessibilityExtensionRecoveryStrategyTest =
+    class extends ChromeVoxNextE2ETest {
+  constructor() {
+    super();
+  }
+};
+
+
+TEST_F(
+    'AccessibilityExtensionRecoveryStrategyTest', 'ReparentedRecovery',
+    function() {
+      this.runWithLoadedTree(
+          `
+    <input type="text"></input>
+    <p id="p">hi</p>
+    <button id="go"</button>
+    <script>
+      document.getElementById('go').addEventListener('click', function() {
+        let p = document.getElementById('p');
+        p.remove();
+        document.body.appendChild(p);
+      });
+    </script>
+  `,
+          function(root) {
+            const p = root.find({role: RoleType.PARAGRAPH});
+            const s = root.find({role: RoleType.STATIC_TEXT});
+            const b = root.find({role: RoleType.BUTTON});
+            const bAncestryRecovery = new AncestryRecoveryStrategy(b);
+            const pAncestryRecovery = new AncestryRecoveryStrategy(p);
+            const sAncestryRecovery = new AncestryRecoveryStrategy(s);
+            const bTreePathRecovery = new TreePathRecoveryStrategy(b);
+            const pTreePathRecovery = new TreePathRecoveryStrategy(p);
+            const sTreePathRecovery = new TreePathRecoveryStrategy(s);
+            this.listenOnce(b, 'clicked', function() {
+              assertFalse(
+                  bAncestryRecovery.requiresRecovery(),
+                  'bAncestryRecovery.requiresRecovery');
+              assertTrue(
+                  pAncestryRecovery.requiresRecovery(),
+                  'pAncestryRecovery.requiresRecovery()');
+              assertTrue(
+                  sAncestryRecovery.requiresRecovery(),
+                  'sAncestryRecovery.requiresRecovery()');
+              assertFalse(
+                  bTreePathRecovery.requiresRecovery(),
+                  'bTreePathRecovery.requiresRecovery()');
+              assertTrue(
+                  pTreePathRecovery.requiresRecovery(),
+                  'pTreePathRecovery.requiresRecovery()');
+              assertTrue(
+                  sTreePathRecovery.requiresRecovery(),
+                  'sTreePathRecovery.requiresRecovery()');
+
+              assertEquals(RoleType.BUTTON, bAncestryRecovery.node.role);
+              assertEquals(root, pAncestryRecovery.node);
+              assertEquals(root, sAncestryRecovery.node);
+
+              assertEquals(b, bTreePathRecovery.node);
+              assertEquals(b, pTreePathRecovery.node);
+              assertEquals(b, sTreePathRecovery.node);
+
+              assertFalse(
+                  bAncestryRecovery.requiresRecovery(),
+                  'bAncestryRecovery.requiresRecovery()');
+              assertFalse(
+                  pAncestryRecovery.requiresRecovery(),
+                  'pAncestryRecovery.requiresRecovery()');
+              assertFalse(
+                  sAncestryRecovery.requiresRecovery(),
+                  'sAncestryRecovery.requiresRecovery()');
+              assertFalse(
+                  bTreePathRecovery.requiresRecovery(),
+                  'bTreePathRecovery.requiresRecovery()');
+              assertFalse(
+                  pTreePathRecovery.requiresRecovery(),
+                  'pTreePathRecovery.requiresRecovery()');
+              assertFalse(
+                  sTreePathRecovery.requiresRecovery(),
+                  'sTreePathRecovery.requiresRecovery()');
+            });
+            // Trigger the change.
+            b.doDefault();
+          });
+    });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/string_util.js b/chrome/browser/resources/chromeos/accessibility/common/string_util.js
similarity index 100%
rename from chrome/browser/resources/chromeos/accessibility/chromevox/common/string_util.js
rename to chrome/browser/resources/chromeos/accessibility/common/string_util.js
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog_old.html b/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog_old.html
index 33ebd4c..043b3ad1 100644
--- a/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog_old.html
+++ b/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog_old.html
@@ -17,6 +17,7 @@
 -->
 <dom-module id="oobe-adaptive-dialog">
   <template>
+    <style include="oobe-dialog-host"></style>
     <oobe-dialog id="dialog" has-buttons hide-shadow$="[[hideShadow]]"
         no-lazy$="[[noLazy]]" no-header$="[[noHeader]]"
         no-footer-padding$="[[noFooterPadding]]"
@@ -32,4 +33,3 @@
   </template>
   <script src="oobe_adaptive_dialog.js"></script>
 </dom-module>
-
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog_old.js b/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog_old.js
index 58690ba..d97c38cc 100644
--- a/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog_old.js
+++ b/chrome/browser/resources/chromeos/login/components/oobe_adaptive_dialog/oobe_adaptive_dialog_old.js
@@ -66,7 +66,7 @@
    * This is called from oobe_welcome when this dialog is shown.
    */
   show() {
-    this.$.show();
+    this.$.dialog.show();
   },
 
 });
diff --git a/chrome/browser/resources/chromeos/login/debug/debug.js b/chrome/browser/resources/chromeos/login/debug/debug.js
index 11cbb1a..ee3a24ee 100644
--- a/chrome/browser/resources/chromeos/login/debug/debug.js
+++ b/chrome/browser/resources/chromeos/login/debug/debug.js
@@ -898,14 +898,26 @@
       states: [
         {
           id: 'WithOptionToSubscribe',
-          trigger: (screen) => {
-            screen.setOptInVisibility(true);
+          data: {
+            optInVisibility: true,
+            optInDefaultState: true,
+            legalFooterVisibility: false,
           },
         },
         {
           id: 'NoOptionToSubscribe',
-          trigger: (screen) => {
-            screen.setOptInVisibility(false);
+          data: {
+            optInVisibility: false,
+            optInDefaultState: false,
+            legalFooterVisibility: false,
+          },
+        },
+        {
+          id: 'WithLegalFooter',
+          data: {
+            optInVisibility: true,
+            optInDefaultState: true,
+            legalFooterVisibility: true,
           },
         },
       ],
diff --git a/chrome/browser/resources/chromeos/login/marketing_opt_in.css b/chrome/browser/resources/chromeos/login/marketing_opt_in.css
index da9cf53..e6886280 100644
--- a/chrome/browser/resources/chromeos/login/marketing_opt_in.css
+++ b/chrome/browser/resources/chromeos/login/marketing_opt_in.css
@@ -31,6 +31,15 @@
   line-height: 20px;
 }
 
+.legal-info {
+  color: var(--google-grey-700);
+  margin-top: 20px;
+}
+
+.legal-info-address {
+  margin-top: 10px;
+}
+
 .marketing-option hd-iron-icon {
   --iron-icon-height: 20px;
   --iron-icon-width: 20px;
diff --git a/chrome/browser/resources/chromeos/login/marketing_opt_in.html b/chrome/browser/resources/chromeos/login/marketing_opt_in.html
index cd292cb..830843ba 100644
--- a/chrome/browser/resources/chromeos/login/marketing_opt_in.html
+++ b/chrome/browser/resources/chromeos/login/marketing_opt_in.html
@@ -64,10 +64,20 @@
               aria-labelledby="chromebookUpdatesOptionLabel">
           </cr-toggle>
         </div>
-        <div class="marketing-animation-container">
+        <div id="animation" class="marketing-animation-container"
+            hidden="[[hasLegalFooter_]]">
           <cr-lottie class="marketing-animation" animation-url="all_set.json">
           </cr-lottie>
         </div>
+        <div id="legalFooter" hidden="[[!hasLegalFooter_]]" class="legal-info">
+          <div>
+            [[i18nDynamic(locale, 'marketingOptInScreenFooterNotice')]]
+          </div>
+          <div class="legal-info-address">
+            Google LLC, 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA
+            <div>www.google.com</div>
+          </div>
+        </div>
       </div>
       <div slot="bottom-buttons" class="layout horizontal justified">
         <div>
diff --git a/chrome/browser/resources/chromeos/login/marketing_opt_in.js b/chrome/browser/resources/chromeos/login/marketing_opt_in.js
index 01a57b8..8d4327f 100644
--- a/chrome/browser/resources/chromeos/login/marketing_opt_in.js
+++ b/chrome/browser/resources/chromeos/login/marketing_opt_in.js
@@ -36,6 +36,15 @@
       type: Boolean,
       value: false,
     },
+
+    /**
+     * Whether a verbose footer will be shown to the user containing some legal
+     *  information such as the Google address. Currently shown for Canada only.
+     */
+    hasLegalFooter_: {
+      type: Boolean,
+      value: false,
+    },
   },
 
   behaviors: [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior],
@@ -44,9 +53,7 @@
   // clang-format off
   EXTERNAL_API: [
     'updateA11ySettingsButtonVisibility',
-    'updateA11yNavigationButtonToggle',
-    'setOptInVisibility',
-    'setEmailToggleState'
+    'updateA11yNavigationButtonToggle'
   ],
   // clang-format on
 
@@ -63,7 +70,14 @@
   },
 
   /** Called when dialog is shown */
-  onBeforeShow() {
+  onBeforeShow(data) {
+    this.marketingOptInVisible_ =
+        'optInVisibility' in data && data.optInVisibility;
+    this.$.chromebookUpdatesOption.checked =
+        'optInDefaultState' in data && data.optInDefaultState;
+    this.hasLegalFooter_ =
+        'legalFooterVisibility' in data && data.legalFooterVisibility;
+
     this.isAccessibilitySettingsShown_ = false;
     this.setAnimationPlay_(true);
     this.$.marketingOptInOverviewDialog.show();
@@ -103,21 +117,6 @@
   },
 
   /**
-   * @param {boolean} visible Whether the email opt-in toggle should be visible
-   */
-  setOptInVisibility(visible) {
-    this.marketingOptInVisible_ = visible;
-  },
-
-  /**
-   * @param {boolean} checked Whether the email opt-in toggle should be checked
-   * or unchecked.
-   */
-  setEmailToggleState(checked) {
-    this.$.chromebookUpdatesOption.checked = checked;
-  },
-
-  /**
    * This is the 'on-tap' event handler for the accessibility settings link and
    * for the back button on the accessibility page.
    * @private
diff --git a/chrome/browser/resources/pdf/constants.js b/chrome/browser/resources/pdf/constants.js
index df87987..45661bbe 100644
--- a/chrome/browser/resources/pdf/constants.js
+++ b/chrome/browser/resources/pdf/constants.js
@@ -22,6 +22,7 @@
  *   author: string,
  *   canSerializeDocument: boolean,
  *   creator: string,
+ *   linearized: boolean,
  *   producer: string,
  *   subject: string,
  *   title: string,
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
index 6235432..f16fcfe 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
@@ -221,12 +221,14 @@
   /** @private */
   onPresentClick_() {
     assert(this.presentationModeEnabled);
+    PDFMetrics.record(UserAction.PRESENT);
     this.getMenu_().close();
     this.dispatchEvent(new CustomEvent('present-click'));
   }
 
   /** @private */
   onPropertiesClick_() {
+    PDFMetrics.record(UserAction.PROPERTIES);
     this.getMenu_().close();
     this.dispatchEvent(new CustomEvent('properties-click'));
   }
diff --git a/chrome/browser/resources/pdf/elements/viewer-properties-dialog.html b/chrome/browser/resources/pdf/elements/viewer-properties-dialog.html
index 7279aad..31bcc0b8 100644
--- a/chrome/browser/resources/pdf/elements/viewer-properties-dialog.html
+++ b/chrome/browser/resources/pdf/elements/viewer-properties-dialog.html
@@ -29,7 +29,11 @@
 
   .value {
     color: var(--cr-secondary-text-color);
+    max-width: 300px;
     min-width: 200px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
   }
 </style>
 <cr-dialog show-on-attach>
@@ -38,7 +42,7 @@
     <table>
       <tr>
         <td class="name">$i18n{propertiesFileName}</td>
-        <td class="value" id="file-name">-</td>
+        <td class="value" id="file-name">[[fileName]]</td>
       </tr>
       <tr class="break">
         <td class="name">$i18n{propertiesFileSize}</td>
@@ -94,7 +98,7 @@
       </tr>
       <tr>
         <td class="name">$i18n{propertiesPageCount}</td>
-        <td class="value" id="page-count">-</td>
+        <td class="value" id="page-count">[[pageCount]]</td>
       </tr>
       <tr class="break">
         <td class="name">$i18n{propertiesPageSize}</td>
@@ -102,7 +106,11 @@
       </tr>
       <tr>
         <td class="name">$i18n{propertiesFastWebView}</td>
-        <td class="value" id="fast-web-view">-</td>
+        <td class="value" id="fast-web-view">
+          [[getFastWebViewValue_('$i18nPolymer{propertiesFastWebViewYes}',
+              '$i18nPolymer{propertiesFastWebViewNo}',
+              documentMetadata.linearized)]]
+        </td>
       </tr>
     </table>
   </div>
diff --git a/chrome/browser/resources/pdf/elements/viewer-properties-dialog.js b/chrome/browser/resources/pdf/elements/viewer-properties-dialog.js
index 869678f..d791c83 100644
--- a/chrome/browser/resources/pdf/elements/viewer-properties-dialog.js
+++ b/chrome/browser/resources/pdf/elements/viewer-properties-dialog.js
@@ -23,6 +23,10 @@
     return {
       /** @type {!DocumentMetadata} */
       documentMetadata: Object,
+
+      fileName: String,
+
+      pageCount: Number,
     };
   }
 
@@ -36,6 +40,17 @@
   }
 
   /**
+   * @param {string} yesLabel
+   * @param {string} noLabel
+   * @param {boolean} linearized
+   * @return {string}
+   * @private
+   */
+  getFastWebViewValue_(yesLabel, noLabel, linearized) {
+    return linearized ? yesLabel : noLabel;
+  }
+
+  /**
    * @param {string} value
    * @return {string}
    * @private
diff --git a/chrome/browser/resources/pdf/metrics.js b/chrome/browser/resources/pdf/metrics.js
index 83f8fa5..90ec642 100644
--- a/chrome/browser/resources/pdf/metrics.js
+++ b/chrome/browser/resources/pdf/metrics.js
@@ -212,7 +212,15 @@
   TOGGLE_DISPLAY_ANNOTATIONS_FIRST: 59,
   TOGGLE_DISPLAY_ANNOTATIONS: 60,
 
-  NUMBER_OF_ACTIONS: 61,
+  // Recorded when the present menu item is clicked.
+  PRESENT_FIRST: 61,
+  PRESENT: 62,
+
+  // Recorded when the document properties menu item is clicked.
+  PROPERTIES_FIRST: 63,
+  PROPERTIES: 64,
+
+  NUMBER_OF_ACTIONS: 65,
 };
 
 // Map from UserAction to the 'FIRST' action. These metrics are recorded
@@ -339,4 +347,12 @@
     UserAction.TOGGLE_DISPLAY_ANNOTATIONS,
     UserAction.TOGGLE_DISPLAY_ANNOTATIONS_FIRST,
   ],
+  [
+    UserAction.PRESENT,
+    UserAction.PRESENT_FIRST,
+  ],
+  [
+    UserAction.PROPERTIES,
+    UserAction.PROPERTIES_FIRST,
+  ],
 ]);
diff --git a/chrome/browser/resources/pdf/pdf_viewer.html b/chrome/browser/resources/pdf/pdf_viewer.html
index ae8986eb..4cd16fb 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.html
+++ b/chrome/browser/resources/pdf/pdf_viewer.html
@@ -226,8 +226,8 @@
 
 <template is="dom-if" if="[[showPropertiesDialog_]]" restamp>
   <viewer-properties-dialog id="properties-dialog"
-      document-metadata="[[documentMetadata_]]"
-      on-close="onPropertiesDialogClose_">
+      document-metadata="[[documentMetadata_]]" file-name="[[fileName_]]"
+      page-count="[[docLength_]]" on-close="onPropertiesDialogClose_">
   </viewer-properties-dialog>
 </template>
 
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
index 71b59c0..8246190 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.js
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -182,6 +182,9 @@
       },
 
       /** @private */
+      fileName_: String,
+
+      /** @private */
       hadPassword_: {
         type: Boolean,
         value: false,
@@ -257,10 +260,7 @@
       },
 
       /** @private */
-      title_: {
-        type: String,
-        value: '',
-      },
+      title_: String,
 
       /** @private */
       twoUpViewEnabled_: {
@@ -405,7 +405,9 @@
         () => chrome.mimeHandlerPrivate.setShowBeforeUnloadDialog(true));
     // </if>
 
-    this.title_ = getFilenameFromURL(this.originalUrl);
+    this.fileName_ = getFilenameFromURL(this.originalUrl);
+    this.title_ = this.fileName_;
+
     if (this.toolbarEnabled_) {
       this.getToolbar_().hidden = false;
     }
@@ -1060,8 +1062,7 @@
    */
   setDocumentMetadata_(metadata) {
     this.documentMetadata_ = metadata;
-    this.title_ =
-        this.documentMetadata_.title || getFilenameFromURL(this.originalUrl);
+    this.title_ = this.documentMetadata_.title || this.fileName_;
     document.title = this.title_;
     this.canSerializeDocument_ = this.documentMetadata_.canSerializeDocument;
   }
diff --git a/chrome/browser/resources/settings/site_settings/chooser_exception_list.js b/chrome/browser/resources/settings/site_settings/chooser_exception_list.js
index bbab832..89328e6 100644
--- a/chrome/browser/resources/settings/site_settings/chooser_exception_list.js
+++ b/chrome/browser/resources/settings/site_settings/chooser_exception_list.js
@@ -197,7 +197,7 @@
 
     if (!this.updateList(
             'chooserExceptions', x => x.displayName, exceptions,
-            true /* identityBasedUpdate= */)) {
+            true /* uidBasedUpdate */)) {
       // The chooser objects have not been changed, so check if their site
       // permissions have changed. The |exceptions| and |this.chooserExceptions|
       // arrays should be the same length.
diff --git a/chrome/browser/resources/tab_search/BUILD.gn b/chrome/browser/resources/tab_search/BUILD.gn
index ab330aa6..a32940b 100644
--- a/chrome/browser/resources/tab_search/BUILD.gn
+++ b/chrome/browser/resources/tab_search/BUILD.gn
@@ -182,7 +182,6 @@
   deps = [
     "//third_party/polymer/v3_0/components-chromium/iron-selector:iron-selector",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js:list_property_update_behavior.m",
   ]
 }
 
diff --git a/chrome/browser/resources/tab_search/app.html b/chrome/browser/resources/tab_search/app.html
index 78cc37b..c054c21 100644
--- a/chrome/browser/resources/tab_search/app.html
+++ b/chrome/browser/resources/tab_search/app.html
@@ -58,7 +58,7 @@
     search-result-text="[[searchResultText_]]">
 </tab-search-search-field>
 <div hidden="[[!filteredOpenTabs_.length]]">
-  <infinite-list id="tabsList" items="[[filteredOpenTabs_]]">
+  <infinite-list id="tabsList" items="[[filteredOpenTabs_]]" >
     <template is="dom-repeat">
       <tab-search-item id="[[item.tab.tabId]]" aria-label="[[ariaLabel_(item)]]"
           class="mwb-list-item" data="[[item]]" on-click="onItemClick_"
diff --git a/chrome/browser/resources/tab_search/app.js b/chrome/browser/resources/tab_search/app.js
index 3d28fb4..6f154ac1 100644
--- a/chrome/browser/resources/tab_search/app.js
+++ b/chrome/browser/resources/tab_search/app.js
@@ -40,9 +40,10 @@
         value: '',
       },
 
-      /** @private {?Array<!TabData>}*/
+      /** @private {?Array<!WindowTabs>} */
       openTabs_: {
         type: Array,
+        observer: 'openTabsChanged_',
       },
 
       /** @private {!Array<!TabData>} */
@@ -168,7 +169,7 @@
           'Tabs.TabSearch.WebUI.TabListDataReceived',
           Math.round(Date.now() - getTabsStartTimestamp));
 
-      this.openTabsChanged_(profileTabs.windows);
+      this.openTabs_ = profileTabs.windows;
     });
   }
 
@@ -177,13 +178,19 @@
    * @private
    */
   onTabUpdated_(updatedTab) {
-    // Replace the tab with the same tabId and trigger rerender.
-    for (let i = 0; i < this.openTabs_.length; ++i) {
-      if (this.openTabs_[i].tab.tabId === updatedTab.tabId) {
-        this.openTabs_[i] =
-            this.tabData_(updatedTab, this.openTabs_[i].inActiveWindow);
-        this.updateFilteredTabs_(this.openTabs_);
-        return;
+    const updatedTabId = updatedTab.tabId;
+    const windows = this.openTabs_;
+    if (windows) {
+      for (const window of windows) {
+        const {tabs} = window;
+        for (let i = 0; i < tabs.length; ++i) {
+          // Replace the tab with the same tabId and trigger rerender.
+          if (tabs[i].tabId === updatedTabId) {
+            tabs[i] = updatedTab;
+            this.openTabs_ = windows.concat();
+            return;
+          }
+        }
       }
     }
   }
@@ -193,21 +200,14 @@
    * @private
    */
   onTabsRemoved_(tabIds) {
-    if (!this.openTabs_) {
-      return;
-    }
-
-    const ids = new Set(tabIds);
-    // Splicing in descending index order to avoid affecting preceding indices
-    // that are to be removed.
-    for (let i = this.openTabs_.length - 1; i >= 0; i--) {
-      if (ids.has(this.openTabs_[i].tab.tabId)) {
-        this.openTabs_.splice(i, 1);
+    const windows = this.openTabs_;
+    if (windows) {
+      const ids = new Set(tabIds);
+      for (const window of windows) {
+        window.tabs = window.tabs.filter(tab => (!ids.has(tab.tabId)));
       }
+      this.openTabs_ = windows.concat();
     }
-
-    this.filteredOpenTabs_ =
-        this.filteredOpenTabs_.filter(tabData => !ids.has(tabData.tab.tabId));
   }
 
   /**
@@ -304,17 +304,11 @@
   }
 
   /**
-   * @param {!Array<!WindowTabs>} newOpenWindowTabs
+   * @param {!Array<!WindowTabs>} newOpenTabs
    * @private
    */
-  openTabsChanged_(newOpenWindowTabs) {
-    this.openTabs_ = [];
-    newOpenWindowTabs.forEach(({active, tabs}) => {
-      tabs.forEach(tab => {
-        this.openTabs_.push(this.tabData_(tab, active));
-      });
-    });
-    this.updateFilteredTabs_(this.openTabs_);
+  openTabsChanged_(newOpenTabs) {
+    this.updateFilteredTabs_(newOpenTabs);
 
     // If there was no previously selected index, set the first item as
     // selected; else retain the currently selected index. If the list
@@ -421,22 +415,19 @@
   }
 
   /**
-   * @param {!Tab} tab
-   * @param {boolean} inActiveWindow
-   * @return {!TabData}
+   * @param {!Array<!WindowTabs>} windowTabs
    * @private
    */
-  tabData_(tab, inActiveWindow) {
-    const hostname = new URL(tab.url).hostname;
-    return /** @type {!TabData} */ ({hostname, inActiveWindow, tab});
-  }
-
-  /**
-   * @param {!Array<!TabData>} tabs
-   * @private
-   */
-  updateFilteredTabs_(tabs) {
-    tabs.sort((a, b) => {
+  updateFilteredTabs_(windowTabs) {
+    const result = [];
+    windowTabs.forEach(window => {
+      window.tabs.forEach(tab => {
+        const hostname = new URL(tab.url).hostname;
+        const inActiveWindow = window.active;
+        result.push({hostname, inActiveWindow, tab});
+      });
+    });
+    result.sort((a, b) => {
       // Move the active tab to the bottom of the list
       // because it's not likely users want to click on it.
       if (this.moveActiveTabToBottom_) {
@@ -453,9 +444,8 @@
               a.tab.lastActiveTimeTicks.internalValue) :
           0;
     });
-
     this.filteredOpenTabs_ =
-        fuzzySearch(this.searchText_, tabs, this.fuzzySearchOptions_);
+        fuzzySearch(this.searchText_, result, this.fuzzySearchOptions_);
     this.searchResultText_ = this.getA11ySearchResultText_();
   }
 
diff --git a/chrome/browser/resources/tab_search/fuzzy_search.js b/chrome/browser/resources/tab_search/fuzzy_search.js
index b2a6950..88f08205 100644
--- a/chrome/browser/resources/tab_search/fuzzy_search.js
+++ b/chrome/browser/resources/tab_search/fuzzy_search.js
@@ -11,12 +11,11 @@
  * @param {string} input
  * @param {!Array<!TabData>} records
  * @param {!Object} options
- * @return {!Array<!TabData>} A new array of entries satisfying the input. If no
- *     search input is present, returns a shallow copy of the records.
+ * @return {!Array<!TabData>}
  */
 export function fuzzySearch(input, records, options) {
   if (input.length === 0) {
-    return [...records];
+    return records;
   }
   // Fuse does not handle exact match searches well. It indiscriminately
   // searches for direct matches that appear anywhere in the string. This
diff --git a/chrome/browser/resources/tab_search/infinite_list.html b/chrome/browser/resources/tab_search/infinite_list.html
index 55b5dfe2..2778c25bc 100644
--- a/chrome/browser/resources/tab_search/infinite_list.html
+++ b/chrome/browser/resources/tab_search/infinite_list.html
@@ -9,6 +9,7 @@
 </style>
 <div id="items">
   <iron-selector id="selector" on-keydown="onKeyDown_"
+      on-iron-items-changed="updateScrollerSize_"
       on-iron-select="onSelectedChanged_" role="listbox"
       selected-class="selected">
     <slot></slot>
diff --git a/chrome/browser/resources/tab_search/infinite_list.js b/chrome/browser/resources/tab_search/infinite_list.js
index 38deb66..96e232d 100644
--- a/chrome/browser/resources/tab_search/infinite_list.js
+++ b/chrome/browser/resources/tab_search/infinite_list.js
@@ -20,7 +20,6 @@
 import 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
 
 import {assert, assertInstanceof} from 'chrome://resources/js/assert.m.js';
-import {updateListProperty} from 'chrome://resources/js/list_property_update_behavior.m.js';
 import {listenOnce} from 'chrome://resources/js/util.m.js';
 import {afterNextRender, DomRepeat, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -93,9 +92,9 @@
 
   /** @private */
   getDomItems_() {
-    const selector = /** @type {!IronSelectorElement} */ (this.$.selector);
+    const selectorChildren = this.$.selector.children;
     return Array.prototype.slice.call(
-        selector.children, 0, selector.children.length - 1);
+        selectorChildren, 0, selectorChildren.length - 1);
   }
 
   /**
@@ -156,7 +155,6 @@
       if (aboveScrollTopItemCount + this.chunkItemThreshold >
           this.domRepeat_.items.length) {
         this.ensureDomItemsAvailableStartingAt_(aboveScrollTopItemCount);
-        this.updateScrollerSize_();
       }
     }
   }
@@ -191,13 +189,12 @@
    * @private
    */
   domItemAverageHeight_() {
-    const selector = /** @type {!IronSelectorElement} */ (this.$.selector);
-    if (!selector.items || selector.items.length === 0) {
+    if (!this.$.selector.items || this.$.selector.items.length === 0) {
       return 0;
     }
 
-    const domItemCount = selector.items.length;
-    const lastDomItem = selector.items[domItemCount - 1];
+    const domItemCount = this.$.selector.items.length;
+    const lastDomItem = this.$.selector.items[domItemCount - 1];
     return (lastDomItem.offsetTop + lastDomItem.offsetHeight) / domItemCount;
   }
 
@@ -205,32 +202,17 @@
    * Ensures that when the items property changes, only a chunk of the items
    * needed to fill the current scroll position view are added to the DOM, thus
    * improving rendering performance.
-   *
-   * @param {!Array} newItems
-   * @param {!Array} oldItems
    * @private
    */
-  onItemsChanged_(newItems, oldItems) {
-    if (!this.domRepeat_) {
-      return;
-    }
+  onItemsChanged_() {
+    if (this.domRepeat_ && this.items) {
+      const domItemAvgHeight = this.domItemAverageHeight_();
+      const aboveScrollTopItemCount = domItemAvgHeight !== 0 ?
+          Math.round(this.scrollTop / domItemAvgHeight) :
+          0;
 
-    if (!oldItems || oldItems.length === 0) {
       this.domRepeat_.set('items', []);
-      this.ensureDomItemsAvailableStartingAt_(0);
-      listenOnce(this.$.selector, 'iron-items-changed', () => {
-        this.updateScrollerSize_();
-      });
-
-      return;
-    }
-
-    updateListProperty(
-        this.domRepeat_, 'items', tabData => tabData,
-        newItems.slice(0, this.domRepeat_.items.length),
-        true /* identityBasedUpdate= */);
-
-    if (newItems.length !== oldItems.length) {
+      this.ensureDomItemsAvailableStartingAt_(aboveScrollTopItemCount);
       this.updateScrollerSize_();
     }
   }
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java
index 5c19eff..b6bd06a 100644
--- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java
+++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java
@@ -110,7 +110,7 @@
                 // Pending requests here must be pre-signin request since SigninManager will wait
                 // system accounts been seeded into AccountTrackerService before finishing sign in.
                 ProfileDownloaderJni.get().startFetchingAccountInfoFor(
-                        mProfiles.get(0), mAccountEmails.get(0), mImageSizes.get(0), true);
+                        mProfiles.get(0), mAccountEmails.get(0), mImageSizes.get(0));
                 mProfiles.remove(0);
                 mAccountEmails.remove(0);
                 mImageSizes.remove(0);
@@ -140,8 +140,7 @@
             PendingProfileDownloads.get().pendProfileDownload(profile, accountEmail, imageSize);
             return;
         }
-        ProfileDownloaderJni.get().startFetchingAccountInfoFor(
-                profile, accountEmail, imageSize, /* isPreSignin= */ true);
+        ProfileDownloaderJni.get().startFetchingAccountInfoFor(profile, accountEmail, imageSize);
     }
 
     @VisibleForTesting
@@ -155,7 +154,6 @@
 
     @NativeMethods
     interface Natives {
-        void startFetchingAccountInfoFor(
-                Profile profile, String accountEmail, int imageSize, boolean isPreSignin);
+        void startFetchingAccountInfoFor(Profile profile, String accountEmail, int imageSize);
     }
 }
diff --git a/chrome/browser/signin/services/android/junit/src/org/chromium/chrome/browser/signin/services/ProfileDownloaderTest.java b/chrome/browser/signin/services/android/junit/src/org/chromium/chrome/browser/signin/services/ProfileDownloaderTest.java
index 82269226..17299b4 100644
--- a/chrome/browser/signin/services/android/junit/src/org/chromium/chrome/browser/signin/services/ProfileDownloaderTest.java
+++ b/chrome/browser/signin/services/android/junit/src/org/chromium/chrome/browser/signin/services/ProfileDownloaderTest.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.signin.services;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
@@ -82,10 +81,10 @@
                 ProfileDownloader.PendingProfileDownloads.get();
         verify(mAccountTrackerServiceMock).addSystemAccountsSeededListener(pendingProfileDownloads);
         verify(mProfileDownloaderNativeMock, never())
-                .startFetchingAccountInfoFor(any(), anyString(), anyInt(), anyBoolean());
+                .startFetchingAccountInfoFor(any(), anyString(), anyInt());
         pendingProfileDownloads.onSystemAccountsSeedingComplete();
         verify(mProfileDownloaderNativeMock)
-                .startFetchingAccountInfoFor(mProfileMock, ACCOUNT_EMAIL, IMAGE_SIZE, true);
+                .startFetchingAccountInfoFor(mProfileMock, ACCOUNT_EMAIL, IMAGE_SIZE);
     }
 
     @Test
@@ -97,7 +96,7 @@
         verify(mAccountTrackerServiceMock, never())
                 .addSystemAccountsSeededListener(pendingProfileDownloads);
         verify(mProfileDownloaderNativeMock)
-                .startFetchingAccountInfoFor(mProfileMock, ACCOUNT_EMAIL, IMAGE_SIZE, true);
+                .startFetchingAccountInfoFor(mProfileMock, ACCOUNT_EMAIL, IMAGE_SIZE);
     }
 
     @Test
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
index df830c42..c3a6646 100644
--- a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
+++ b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
@@ -10,6 +10,7 @@
 
 #include "base/json/json_writer.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/system/sys_info.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -366,7 +367,12 @@
     saw_espeak |=
         voice.engine_id == extension_misc::kEspeakSpeechSynthesisExtensionId;
   }
-  return saw_google_tts && saw_espeak;
+
+  // When running on a real Chrome OS environment, require both Google tts and
+  // Espeak to be initialized; otherwise, only check for Espeak (i.e. on a
+  // non-Chrome OS linux system running the CHrome OS variant of Chrome).
+  return base::SysInfo::IsRunningOnChromeOS() ? (saw_google_tts && saw_espeak)
+                                              : saw_espeak;
 #else
   // Vacuously; no built in engines on other platforms yet. TODO: network tts?
   return true;
diff --git a/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc b/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
index 9b9af29b..a6f8c85 100644
--- a/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
+++ b/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
@@ -29,6 +29,7 @@
 #include "components/subresource_filter/core/common/activation_decision.h"
 #include "components/subresource_filter/core/common/activation_scope.h"
 #include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
@@ -97,6 +98,18 @@
   }
 }
 
+subresource_filter::mojom::ActivationLevel
+ChromeSubresourceFilterClient::OnPageActivationComputed(
+    content::NavigationHandle* navigation_handle,
+    subresource_filter::mojom::ActivationLevel initial_activation_level,
+    subresource_filter::ActivationDecision* decision) {
+  // TODO(crbug.com/1116095): Once SafeBrowsingActivationThrottle knows about
+  // ProfileInteractionManager, it can invoke ProfileInteractionManager directly
+  // and SubresourceFilterClient::OnPageActivationComputed() can be eliminated.
+  return profile_interaction_manager_->OnPageActivationComputed(
+      navigation_handle, initial_activation_level, decision);
+}
+
 void ChromeSubresourceFilterClient::OnAdsViolationTriggered(
     content::RenderFrameHost* rfh,
     subresource_filter::mojom::AdsViolation triggered_violation) {
@@ -116,11 +129,6 @@
                                : nullptr;
 }
 
-subresource_filter::ProfileInteractionManager*
-ChromeSubresourceFilterClient::GetProfileInteractionManager() {
-  return profile_interaction_manager_.get();
-}
-
 void ChromeSubresourceFilterClient::ShowUI(const GURL& url) {
 #if defined(OS_ANDROID)
   InfoBarService* infobar_service =
diff --git a/chrome/browser/subresource_filter/chrome_subresource_filter_client.h b/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
index 72ee4a3..0ef6322 100644
--- a/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
+++ b/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
@@ -15,11 +15,13 @@
 class GURL;
 
 namespace content {
+class NavigationHandle;
 class WebContents;
 }  // namespace content
 
 namespace subresource_filter {
 class ContentSubresourceFilterThrottleManager;
+class ProfileInteractionManager;
 class SubresourceFilterProfileContext;
 }  // namespace subresource_filter
 
@@ -45,13 +47,15 @@
 
   // SubresourceFilterClient:
   void ShowNotification() override;
+  subresource_filter::mojom::ActivationLevel OnPageActivationComputed(
+      content::NavigationHandle* navigation_handle,
+      subresource_filter::mojom::ActivationLevel initial_activation_level,
+      subresource_filter::ActivationDecision* decision) override;
   void OnAdsViolationTriggered(
       content::RenderFrameHost* rfh,
       subresource_filter::mojom::AdsViolation triggered_violation) override;
   const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
   GetSafeBrowsingDatabaseManager() override;
-  subresource_filter::ProfileInteractionManager* GetProfileInteractionManager()
-      override;
   void OnReloadRequested() override;
 
  private:
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service_android.cc b/chrome/browser/supervised_user/child_accounts/child_account_service_android.cc
index d5185be..72c218e 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service_android.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service_android.cc
@@ -25,14 +25,14 @@
 void ReauthenticateChildAccount(
     content::WebContents* web_contents,
     const std::string& email,
-    const base::RepeatingCallback<void(bool)>& callback) {
+    const base::RepeatingCallback<void()>& on_failure_callback) {
   ui::WindowAndroid* window_android =
       web_contents->GetNativeView()->GetWindowAndroid();
 
   // Make a copy of the callback which can be passed as a pointer through
   // to Java.
   auto callback_copy =
-      std::make_unique<base::RepeatingCallback<void(bool)>>(callback);
+      std::make_unique<base::RepeatingCallback<void()>>(on_failure_callback);
 
   JNIEnv* env = AttachCurrentThread();
   Java_ChildAccountService_reauthenticateChildAccount(
@@ -40,13 +40,11 @@
       reinterpret_cast<jlong>(callback_copy.release()));
 }
 
-void JNI_ChildAccountService_OnReauthenticationResult(
-    JNIEnv* env,
-    jlong jcallbackPtr,
-    jboolean result) {
+void JNI_ChildAccountService_OnReauthenticationFailed(JNIEnv* env,
+                                                      jlong jcallbackPtr) {
   // Cast the pointer value back to a Callback and take ownership of it.
-  std::unique_ptr<base::RepeatingCallback<void(bool)>> callback(
-      reinterpret_cast<base::RepeatingCallback<void(bool)>*>(jcallbackPtr));
+  std::unique_ptr<base::RepeatingCallback<void()>> callback(
+      reinterpret_cast<base::RepeatingCallback<void()>*>(jcallbackPtr));
 
-  callback->Run(result);
+  callback->Run();
 }
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service_android.h b/chrome/browser/supervised_user/child_accounts/child_account_service_android.h
index ba8406fd..de13cbc 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service_android.h
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service_android.h
@@ -16,6 +16,6 @@
 void ReauthenticateChildAccount(
     content::WebContents* web_contents,
     const std::string& email,
-    const base::RepeatingCallback<void(bool)>& callback);
+    const base::RepeatingCallback<void()>& on_failure_callback);
 
 #endif  // CHROME_BROWSER_SUPERVISED_USER_CHILD_ACCOUNTS_CHILD_ACCOUNT_SERVICE_ANDROID_H_
diff --git a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
index 274b9bf..f407ea5 100644
--- a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
+++ b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
@@ -148,7 +148,7 @@
     ReauthenticateChildAccount(
         web_contents, account_info.email,
         base::BindRepeating(&SupervisedUserGoogleAuthNavigationThrottle::
-                                OnReauthenticationResult,
+                                OnReauthenticationFailed,
                             weak_ptr_factory_.GetWeakPtr()));
   }
   return content::NavigationThrottle::DEFER;
@@ -161,14 +161,7 @@
 #endif
 }
 
-void SupervisedUserGoogleAuthNavigationThrottle::OnReauthenticationResult(
-    bool reauth_successful) {
-  if (reauth_successful) {
-    // If reauthentication was not successful, wait until the cookies are
-    // refreshed, which will call us back separately.
-    return;
-  }
-
-  // Otherwise cancel immediately.
+void SupervisedUserGoogleAuthNavigationThrottle::OnReauthenticationFailed() {
+  // Cancel the navifation if reauthentication failed.
   CancelDeferredNavigation(content::NavigationThrottle::CANCEL_AND_IGNORE);
 }
diff --git a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h
index bb1758a..8fbb18a 100644
--- a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h
+++ b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h
@@ -42,7 +42,7 @@
 
   ThrottleCheckResult ShouldProceed();
 
-  void OnReauthenticationResult(bool reauth_successful);
+  void OnReauthenticationFailed();
 
   ChildAccountService* child_account_service_;
   base::CallbackListSubscription google_auth_state_subscription_;
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/chrome/browser/supervised_user/supervised_user_interstitial.cc
index ebb4fba..2857fe6 100644
--- a/chrome/browser/supervised_user/supervised_user_interstitial.cc
+++ b/chrome/browser/supervised_user/supervised_user_interstitial.cc
@@ -130,7 +130,7 @@
       details.previous_main_frame_url =
           controller.GetLastCommittedEntry()->GetURL();
     }
-    details.type = content::NAVIGATION_TYPE_NEW_PAGE;
+    details.type = content::NAVIGATION_TYPE_NEW_ENTRY;
     for (int i = service->infobar_count() - 1; i >= 0; --i) {
       infobars::InfoBar* infobar = service->infobar_at(i);
       if (infobar->delegate()->ShouldExpire(
diff --git a/chrome/browser/sync/test/integration/fake_server_invalidation_sender.cc b/chrome/browser/sync/test/integration/fake_server_invalidation_sender.cc
index 66f6a88..ea072bf 100644
--- a/chrome/browser/sync/test/integration/fake_server_invalidation_sender.cc
+++ b/chrome/browser/sync/test/integration/fake_server_invalidation_sender.cc
@@ -19,13 +19,13 @@
 FakeServerInvalidationSender::FakeServerInvalidationSender(
     const std::string& client_id,
     bool self_notify,
-    base::RepeatingCallback<syncer::FCMNetworkHandler*()>
+    base::RepeatingCallback<invalidation::FCMNetworkHandler*()>
         fcm_network_handler_getter)
     : client_id_(client_id),
       self_notify_(self_notify),
       fcm_network_handler_getter_(fcm_network_handler_getter) {}
 
-FakeServerInvalidationSender::~FakeServerInvalidationSender() {}
+FakeServerInvalidationSender::~FakeServerInvalidationSender() = default;
 
 void FakeServerInvalidationSender::OnCommit(
     const std::string& committer_invalidator_client_id,
@@ -33,7 +33,7 @@
   if (!self_notify_ && client_id_ == committer_invalidator_client_id) {
     return;
   }
-  syncer::FCMNetworkHandler* fcm_network_handler =
+  invalidation::FCMNetworkHandler* fcm_network_handler =
       fcm_network_handler_getter_.Run();
   // If there is no FCM network handler registered for this profile, there is
   // nothing to do. This could be the case during test Setup phase because the
diff --git a/chrome/browser/sync/test/integration/fake_server_invalidation_sender.h b/chrome/browser/sync/test/integration/fake_server_invalidation_sender.h
index 5d95fc3a..198d5b14 100644
--- a/chrome/browser/sync/test/integration/fake_server_invalidation_sender.h
+++ b/chrome/browser/sync/test/integration/fake_server_invalidation_sender.h
@@ -5,12 +5,10 @@
 #ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_FAKE_SERVER_INVALIDATION_SENDER_H_
 #define CHROME_BROWSER_SYNC_TEST_INTEGRATION_FAKE_SERVER_INVALIDATION_SENDER_H_
 
-#include "base/macros.h"
-
 #include "components/sync/base/model_type.h"
 #include "components/sync/test/fake_server/fake_server.h"
 
-namespace syncer {
+namespace invalidation {
 class FCMNetworkHandler;
 }
 
@@ -24,8 +22,12 @@
   FakeServerInvalidationSender(
       const std::string& client_id,
       bool self_notify,
-      base::RepeatingCallback<syncer::FCMNetworkHandler*()>
+      base::RepeatingCallback<invalidation::FCMNetworkHandler*()>
           fcm_network_handler_getter);
+  FakeServerInvalidationSender(const FakeServerInvalidationSender& other) =
+      delete;
+  FakeServerInvalidationSender& operator=(
+      const FakeServerInvalidationSender& other) = delete;
   ~FakeServerInvalidationSender() override;
 
   // FakeServer::Observer implementation.
@@ -35,10 +37,8 @@
  private:
   const std::string client_id_;
   const bool self_notify_;
-  const base::RepeatingCallback<syncer::FCMNetworkHandler*()>
+  const base::RepeatingCallback<invalidation::FCMNetworkHandler*()>
       fcm_network_handler_getter_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeServerInvalidationSender);
 };
 
 }  // namespace fake_server
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 86e24e8..d4e889c 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -135,10 +135,10 @@
 }
 
 class FakePerUserTopicSubscriptionManager
-    : public syncer::PerUserTopicSubscriptionManager {
+    : public invalidation::PerUserTopicSubscriptionManager {
  public:
   explicit FakePerUserTopicSubscriptionManager(PrefService* local_state)
-      : syncer::PerUserTopicSubscriptionManager(
+      : invalidation::PerUserTopicSubscriptionManager(
             /*identity_provider=*/nullptr,
             /*pref_service=*/local_state,
             /*url_loader_factory=*/nullptr,
@@ -146,28 +146,28 @@
             /*migrate_prefs=*/false) {}
   ~FakePerUserTopicSubscriptionManager() override = default;
 
-  void UpdateSubscribedTopics(const syncer::Topics& topics,
+  void UpdateSubscribedTopics(const invalidation::Topics& topics,
                               const std::string& instance_id_token) override {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakePerUserTopicSubscriptionManager);
 };
 
-std::unique_ptr<syncer::FCMNetworkHandler> CreateFCMNetworkHandler(
+std::unique_ptr<invalidation::FCMNetworkHandler> CreateFCMNetworkHandler(
     Profile* profile,
-    std::map<const Profile*, syncer::FCMNetworkHandler*>*
+    std::map<const Profile*, invalidation::FCMNetworkHandler*>*
         profile_to_fcm_network_handler_map,
     gcm::GCMDriver* gcm_driver,
     instance_id::InstanceIDDriver* instance_id_driver,
     const std::string& sender_id,
     const std::string& app_id) {
-  auto handler = std::make_unique<syncer::FCMNetworkHandler>(
+  auto handler = std::make_unique<invalidation::FCMNetworkHandler>(
       gcm_driver, instance_id_driver, sender_id, app_id);
   (*profile_to_fcm_network_handler_map)[profile] = handler.get();
   return handler;
 }
 
-std::unique_ptr<syncer::PerUserTopicSubscriptionManager>
+std::unique_ptr<invalidation::PerUserTopicSubscriptionManager>
 CreatePerUserTopicSubscriptionManager(
     invalidation::IdentityProvider* identity_provider,
     PrefService* local_state,
@@ -177,9 +177,9 @@
   return std::make_unique<FakePerUserTopicSubscriptionManager>(local_state);
 }
 
-syncer::FCMNetworkHandler* GetFCMNetworkHandler(
+invalidation::FCMNetworkHandler* GetFCMNetworkHandler(
     Profile* profile,
-    std::map<const Profile*, syncer::FCMNetworkHandler*>*
+    std::map<const Profile*, invalidation::FCMNetworkHandler*>*
         profile_to_fcm_network_handler_map) {
   // Delivering FCM notifications does not work if explicitly signed-out.
   signin::IdentityManager* identity_manager =
@@ -1064,7 +1064,7 @@
 
 // static
 std::unique_ptr<KeyedService> SyncTest::CreateProfileInvalidationProvider(
-    std::map<const Profile*, syncer::FCMNetworkHandler*>*
+    std::map<const Profile*, invalidation::FCMNetworkHandler*>*
         profile_to_fcm_network_handler_map,
     std::map<const Profile*, std::unique_ptr<instance_id::InstanceIDDriver>>*
         profile_to_instance_id_driver_map,
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h
index cdb6a1a8..5c649b61 100644
--- a/chrome/browser/sync/test/integration/sync_test.h
+++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -360,7 +360,7 @@
                                     Profile::CreateStatus status);
 
   static std::unique_ptr<KeyedService> CreateProfileInvalidationProvider(
-      std::map<const Profile*, syncer::FCMNetworkHandler*>*
+      std::map<const Profile*, invalidation::FCMNetworkHandler*>*
           profile_to_fcm_network_handler_map,
       std::map<const Profile*, std::unique_ptr<instance_id::InstanceIDDriver>>*
           profile_to_instance_id_driver_map,
@@ -497,7 +497,7 @@
   // Maps a profile to the corresponding FCMNetworkHandler. Contains one entry
   // per profile. It is used to simulate an incoming FCM messages to different
   // profiles within the FakeServerInvalidationSender.
-  std::map<const Profile*, syncer::FCMNetworkHandler*>
+  std::map<const Profile*, invalidation::FCMNetworkHandler*>
       profile_to_fcm_network_handler_map_;
 
   std::map<const Profile*, std::unique_ptr<instance_id::InstanceIDDriver>>
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc b/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
index 4147b38..71f82294 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
@@ -28,7 +28,7 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/app_sorting.h"
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_sync_test.cc b/chrome/browser/sync/test/integration/two_client_web_apps_sync_test.cc
index 2c830c9..76d090a 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_sync_test.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/web_applications/test/web_app_install_observer.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_utils.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
index fbd7580..4d5c9eb 100644
--- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
+++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -909,12 +909,12 @@
       ->SendNavigateWithTransition(pending_id, false, url,
                                    ui::PAGE_TRANSITION_TYPED);
 
-  // Test that we are really getting a same page navigation, the test would be
+  // Test that we are really getting a same entry navigation, the test would be
   // useless if it was not the case.
   const content::LoadCommittedDetails& nav_details =
       nav_observer.load_committed_details();
   EXPECT_TRUE(nav_details.entry != NULL);  // There was a navigation.
-  EXPECT_EQ(content::NAVIGATION_TYPE_SAME_PAGE, nav_details.type);
+  EXPECT_EQ(content::NAVIGATION_TYPE_SAME_ENTRY, nav_details.type);
 
   // The TranslateManager class processes the navigation entry committed
   // notification in a posted task; process that task.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 3607a31..7db785ae 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -535,7 +535,7 @@
     "//components/viz/host",
     "//components/web_cache/browser",
     "//components/web_resource",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//components/webrtc_logging/browser",
     "//content/app/resources",
     "//content/browser/webrtc/resources",
diff --git a/chrome/browser/ui/ash/capture_mode_browsertest.cc b/chrome/browser/ui/ash/capture_mode_browsertest.cc
index 78fcb9d..82d9893 100644
--- a/chrome/browser/ui/ash/capture_mode_browsertest.cc
+++ b/chrome/browser/ui/ash/capture_mode_browsertest.cc
@@ -6,9 +6,15 @@
 #include "ash/public/cpp/capture_mode_test_api.h"
 #include "ash/public/cpp/test/shell_test_api.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test.h"
+#include "ui/aura/window.h"
+#include "ui/events/test/event_generator.h"
 
+// Testing class to test CrOS capture mode, which is a feature to take
+// screenshots and record video.
 class CaptureModeBrowserTest : public InProcessBrowserTest {
  public:
   CaptureModeBrowserTest() = default;
@@ -27,8 +33,16 @@
 };
 
 IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest, ContextMenuStaysOpen) {
+  // Right click the desktop to open a context menu.
+  aura::Window* browser_window = browser()->window()->GetNativeWindow();
+  const gfx::Point point_on_desktop(1, 1);
+  ASSERT_FALSE(browser_window->bounds().Contains(point_on_desktop));
+
+  ui::test::EventGenerator event_generator(browser_window->GetRootWindow(),
+                                           point_on_desktop);
+  event_generator.ClickRightButton();
+
   ash::ShellTestApi shell_test_api;
-  shell_test_api.ShowContextMenu();
   ASSERT_TRUE(shell_test_api.IsContextMenuShown());
 
   ash::CaptureModeTestApi().StartForWindow(/*for_video=*/false);
diff --git a/chrome/browser/ui/ash/clipboard_image_model_factory_impl.cc b/chrome/browser/ui/ash/clipboard_image_model_factory_impl.cc
index 78ffea7..9fd23be8 100644
--- a/chrome/browser/ui/ash/clipboard_image_model_factory_impl.cc
+++ b/chrome/browser/ui/ash/clipboard_image_model_factory_impl.cc
@@ -53,7 +53,12 @@
 void ClipboardImageModelFactoryImpl::Deactivate() {
   active_ = false;
 
-  if (!request_ || !request_->IsModifyingClipboard())
+  // Rendering will not stop if |active_until_empty_| has been set true by a
+  // call to `RenderCurrentPendingRequests()`.
+  if (active_until_empty_)
+    return;
+
+  if ((!request_ || !request_->IsModifyingClipboard()))
     return;
 
   // Stop the currently running request if it is modifying the clipboard.
@@ -63,6 +68,11 @@
   pending_list_.emplace_front(request_->StopAndGetParams());
 }
 
+void ClipboardImageModelFactoryImpl::RenderCurrentPendingRequests() {
+  active_until_empty_ = true;
+  StartNextRequest();
+}
+
 void ClipboardImageModelFactoryImpl::OnShutdown() {
   // Reset |request_| to drop its reference to Profile, specifically the
   // RenderProcessHost of its WebContents.
@@ -70,7 +80,10 @@
 }
 
 void ClipboardImageModelFactoryImpl::StartNextRequest() {
-  if (pending_list_.empty() || !active_ ||
+  if (pending_list_.empty())
+    active_until_empty_ = false;
+
+  if (pending_list_.empty() || (!active_ && !active_until_empty_) ||
       (request_ && request_->IsRunningRequest())) {
     return;
   }
diff --git a/chrome/browser/ui/ash/clipboard_image_model_factory_impl.h b/chrome/browser/ui/ash/clipboard_image_model_factory_impl.h
index f5173be..33c9c0d 100644
--- a/chrome/browser/ui/ash/clipboard_image_model_factory_impl.h
+++ b/chrome/browser/ui/ash/clipboard_image_model_factory_impl.h
@@ -32,6 +32,7 @@
   void CancelRequest(const base::UnguessableToken& id) override;
   void Activate() override;
   void Deactivate() override;
+  void RenderCurrentPendingRequests() override;
   void OnShutdown() override;
 
   // Starts the first request in |pending_list_|.
@@ -48,6 +49,11 @@
   // queued until Activate().
   bool active_ = false;
 
+  // Whether ClipboardImageModelFactoryImpl will render all requests until the
+  // |pending_list_| is empty. When true, all requests will be rendered
+  // regardless of |active_|.
+  bool active_until_empty_ = false;
+
   // Requests which are waiting to be run.
   std::list<ClipboardImageModelRequest::Params> pending_list_;
 
diff --git a/chrome/browser/ui/ash/in_session_auth_dialog_client.cc b/chrome/browser/ui/ash/in_session_auth_dialog_client.cc
index d2baa89..7757b8a 100644
--- a/chrome/browser/ui/ash/in_session_auth_dialog_client.cc
+++ b/chrome/browser/ui/ash/in_session_auth_dialog_client.cc
@@ -32,10 +32,8 @@
 
 namespace {
 
-// TODO(b/156258540): Replace with correct URL once the article is uploaded.
-// This URL is an irrelevant article just for validating functionality.
 const char kInSessionAuthHelpPageUrl[] =
-    "https://support.google.com/chrome/?p=settings_sign_in";
+    "https://support.google.com/chromebook?p=WebAuthn";
 
 InSessionAuthDialogClient* g_auth_dialog_client_instance = nullptr;
 
diff --git a/chrome/browser/ui/extensions/extension_installed_bubble_model_unittest.cc b/chrome/browser/ui/extensions/extension_installed_bubble_model_unittest.cc
index a14d63aa..70e1762 100644
--- a/chrome/browser/ui/extensions/extension_installed_bubble_model_unittest.cc
+++ b/chrome/browser/ui/extensions/extension_installed_bubble_model_unittest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/load_error_reporter.h"
 #include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/common/extensions/api/omnibox.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/browser/extension_system.h"
@@ -39,10 +40,10 @@
 
   void AddOmniboxKeyword(extensions::ExtensionBuilder* builder,
                          const std::string& keyword) {
+    using ManifestKeys = extensions::api::omnibox::ManifestKeys;
     auto info = std::make_unique<base::DictionaryValue>();
-    info->SetStringKey("keyword", keyword);
-    builder->SetManifestKey(extensions::manifest_keys::kOmnibox,
-                            std::move(info));
+    info->SetStringKey(ManifestKeys::Omnibox::kKeyword, keyword);
+    builder->SetManifestKey(ManifestKeys::kOmnibox, std::move(info));
   }
 
   void AddRegularAction(extensions::ExtensionBuilder* builder) {
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
index a954c36..caa94e15 100644
--- a/chrome/browser/ui/hats/hats_service.cc
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -23,7 +23,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "components/metrics_services_manager/metrics_services_manager.h"
-#include "components/prefs/pref_registry_simple.h"
+#include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
@@ -51,11 +51,14 @@
 
 constexpr char kHatsSurveyEnSiteIDDefault[] = "bhej2dndhpc33okm6xexsbyv4y";
 
+// TODO(crbug.com/1160661): When the minimum time between any survey, and the
+// minimum time between a specific survey, are the same, the logic supporting
+// the latter check is superfluous.
 constexpr base::TimeDelta kMinimumTimeBetweenSurveyStarts =
-    base::TimeDelta::FromDays(60);
+    base::TimeDelta::FromDays(180);
 
 constexpr base::TimeDelta kMinimumTimeBetweenAnySurveyStarts =
-    base::TimeDelta::FromDays(7);
+    base::TimeDelta::FromDays(180);
 
 constexpr base::TimeDelta kMinimumTimeBetweenSurveyChecks =
     base::TimeDelta::FromDays(1);
@@ -187,8 +190,11 @@
 HatsService::~HatsService() = default;
 
 // static
-void HatsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterDictionaryPref(prefs::kHatsSurveyMetadata);
+void HatsService::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterDictionaryPref(
+      prefs::kHatsSurveyMetadata,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
 void HatsService::LaunchSurvey(const std::string& trigger,
diff --git a/chrome/browser/ui/hats/hats_service.h b/chrome/browser/ui/hats/hats_service.h
index 2381925..ac14cf0 100644
--- a/chrome/browser/ui/hats/hats_service.h
+++ b/chrome/browser/ui/hats/hats_service.h
@@ -23,8 +23,11 @@
 class WebContents;
 }
 
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
 class Browser;
-class PrefRegistrySimple;
 class Profile;
 
 // Trigger identifiers currently used; duplicates not allowed.
@@ -144,7 +147,7 @@
 
   explicit HatsService(Profile* profile);
 
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
   // Launches survey with identifier |trigger| if appropriate.
   // |success_callback| is called when the survey is shown to the user.
diff --git a/chrome/browser/ui/manifest_web_app_browser_controller.cc b/chrome/browser/ui/manifest_web_app_browser_controller.cc
index 97261a105..c8d8c95 100644
--- a/chrome/browser/ui/manifest_web_app_browser_controller.cc
+++ b/chrome/browser/ui/manifest_web_app_browser_controller.cc
@@ -7,7 +7,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 0258908..ee2b5f6 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -77,7 +77,7 @@
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_service.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 1a711416..7709a297 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -112,7 +112,7 @@
 #include "components/sync/engine/sync_engine_switches.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "components/ukm/content/source_url_recorder.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/buildflags/buildflags.h"
 #include "media/base/media_switches.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 19cc99b..1006ef3 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1419,6 +1419,8 @@
     }
 
     case CommandAddToReadLater: {
+      base::RecordAction(
+          UserMetricsAction("DesktopReadingList.AddItem.FromTabContextMenu"));
       AddToReadLater(GetIndicesForCommand(context_index));
       break;
     }
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc
index b725178..3b8cc4a 100644
--- a/chrome/browser/ui/views/location_bar/star_view.cc
+++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -6,7 +6,10 @@
 
 #include <string>
 
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/defaults.h"
@@ -30,6 +33,25 @@
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/menu/menu_runner.h"
 
+namespace {
+
+// Enumeration of all actions in the star menu.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class Action {
+  kAddBookmarkButton = 0,
+  kEditBookmarkButton = 1,
+  kAddToReadingListButton = 2,
+  kMarkAsReadButton = 3,
+  kMaxValue = kMarkAsReadButton,
+};
+
+void RecordClick(Action item) {
+  base::UmaHistogramEnumeration("Bookmarks.StarEntryPoint.ClickedAction", item);
+}
+
+}  // namespace
+
 StarView::StarView(CommandUpdater* command_updater,
                    Browser* browser,
                    IconLabelBubbleView::Delegate* icon_label_bubble_delegate,
@@ -114,12 +136,18 @@
 void StarView::ExecuteCommand(int command_id, int event_flags) {
   switch (command_id) {
     case StarMenuModel::CommandBookmark:
+      RecordClick(GetActive() ? Action::kEditBookmarkButton
+                              : Action::kAddBookmarkButton);
       chrome::BookmarkCurrentTab(browser_);
       break;
     case StarMenuModel::CommandMoveToReadLater:
+      RecordClick(Action::kAddToReadingListButton);
+      base::RecordAction(base::UserMetricsAction(
+          "DesktopReadingList.AddItem.FromBookmarkIcon"));
       chrome::MoveCurrentTabToReadLater(browser_);
       break;
     case StarMenuModel::CommandMarkAsRead:
+      RecordClick(Action::kMarkAsReadButton);
       chrome::MarkCurrentTabAsReadInReadLater(browser_);
       break;
     default:
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view.cc b/chrome/browser/ui/views/page_action/pwa_install_view.cc
index 8cd6e0f..bd48f0fe 100644
--- a/chrome/browser/ui/views/page_action/pwa_install_view.cc
+++ b/chrome/browser/ui/views/page_action/pwa_install_view.cc
@@ -28,7 +28,7 @@
 #include "components/feature_engagement/public/feature_constants.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/site_engagement/content/site_engagement_service.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/metadata/metadata_impl_macros.h"
 
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
index 8e6d6e3..4a4671a 100644
--- a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
@@ -36,7 +36,7 @@
 #include "components/omnibox/browser/omnibox_popup_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/site_engagement/content/site_engagement_service.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/common/referrer.h"
 #include "content/public/test/browser_test.h"
 #include "extensions/common/extension.h"
diff --git a/chrome/browser/ui/views/read_later/read_later_button.cc b/chrome/browser/ui/views/read_later/read_later_button.cc
index 75b786de..7941d48 100644
--- a/chrome/browser/ui/views/read_later/read_later_button.cc
+++ b/chrome/browser/ui/views/read_later/read_later_button.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/read_later/read_later_button.h"
 
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
 #include "base/strings/string16.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
@@ -119,6 +121,8 @@
     if (webui_bubble_manager_->GetBubbleWidget()) {
       webui_bubble_manager_->CloseBubble();
     } else {
+      base::RecordAction(
+          base::UserMetricsAction("DesktopReadingList.OpenReadingList"));
       webui_bubble_manager_->ShowBubble();
     }
   }
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc
index 1e57de5..70a78509 100644
--- a/chrome/browser/ui/views/tabs/tab_style_views.cc
+++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -971,6 +971,12 @@
              : base::nullopt;
 }
 
+// static
+views::metadata::ValidStrings
+views::metadata::TypeConverter<TabStyle::TabColors>::GetValidStrings() {
+  return ValidStrings();
+}
+
 // TabStyle --------------------------------------------------------------------
 
 TabStyleViews::~TabStyleViews() = default;
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.h b/chrome/browser/ui/views/tabs/tab_style_views.h
index 0a09ef6..4122d876 100644
--- a/chrome/browser/ui/views/tabs/tab_style_views.h
+++ b/chrome/browser/ui/views/tabs/tab_style_views.h
@@ -20,6 +20,7 @@
       views::metadata::ArgType<TabStyle::TabColors> source_value);
   static base::Optional<TabStyle::TabColors> FromString(
       const base::string16& source_value);
+  static views::metadata::ValidStrings GetValidStrings();
 };
 
 class Tab;
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc
index b760a002..a2c89d5 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.cc
@@ -23,6 +23,12 @@
   SetUpLabs();
 }
 
+ChromeLabsBubbleViewModel::ChromeLabsBubbleViewModel(
+    const std::vector<LabInfo>& lab_info)
+    : lab_info_(lab_info) {
+  SetUpLabs();
+}
+
 ChromeLabsBubbleViewModel::~ChromeLabsBubbleViewModel() = default;
 
 const std::vector<LabInfo>& ChromeLabsBubbleViewModel::GetLabInfo() const {
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h
index fa5f953..e3989b4 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h
@@ -32,6 +32,8 @@
 class ChromeLabsBubbleViewModel {
  public:
   ChromeLabsBubbleViewModel();
+  // |lab_info_| will have `lab_info`, and whatever SetUpLabs appends to it.
+  explicit ChromeLabsBubbleViewModel(const std::vector<LabInfo>& lab_info);
   ~ChromeLabsBubbleViewModel();
 
   const std::vector<LabInfo>& GetLabInfo() const;
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button.cc b/chrome/browser/ui/views/toolbar/chrome_labs_button.cc
index 607da64..1aea22c 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_button.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_button.cc
@@ -15,6 +15,8 @@
       views::ButtonController::NotifyAction::kOnPress);
 }
 
+ChromeLabsButton::~ChromeLabsButton() = default;
+
 void ChromeLabsButton::UpdateIcon() {
   UpdateIconsWithStandardColors(kChromeLabsIcon);
 }
@@ -23,11 +25,17 @@
   return "ChromeLabsButton";
 }
 
+void ChromeLabsButton::SetLabInfoForTesting(
+    const std::vector<LabInfo>& test_lab_info) {
+  test_lab_info_ = test_lab_info;
+}
+
 void ChromeLabsButton::ButtonPressed() {
   if (ChromeLabsBubbleView::IsShowing()) {
     ChromeLabsBubbleView::Hide();
     return;
   }
-  ChromeLabsBubbleView::Show(this,
-                             std::make_unique<ChromeLabsBubbleViewModel>());
+  std::unique_ptr<ChromeLabsBubbleViewModel> model =
+      std::make_unique<ChromeLabsBubbleViewModel>(test_lab_info_);
+  ChromeLabsBubbleView::Show(this, std::move(model));
 }
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button.h b/chrome/browser/ui/views/toolbar/chrome_labs_button.h
index 09ef0724..acf3d392 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_button.h
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_button.h
@@ -5,11 +5,13 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_BUTTON_H_
 #define CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_BUTTON_H_
 
+#include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view_model.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 
 class ChromeLabsButton : public ToolbarButton {
  public:
   ChromeLabsButton();
+  ~ChromeLabsButton() override;
 
   // ToolbarButton:
   void UpdateIcon() override;
@@ -17,8 +19,14 @@
   // views::View:
   const char* GetClassName() const override;
 
+  void SetLabInfoForTesting(const std::vector<LabInfo>& test_lab_info);
+
  private:
   void ButtonPressed();
+
+  // Used by tests to customize the LabInfo used to populate the button's menu.
+  // This will be empty in production code.
+  std::vector<LabInfo> test_lab_info_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_BUTTON_H_
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button_unittest.cc b/chrome/browser/ui/views/toolbar/chrome_labs_button_unittest.cc
index 725209d..8143678 100644
--- a/chrome/browser/ui/views/toolbar/chrome_labs_button_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/chrome_labs_button_unittest.cc
@@ -4,15 +4,21 @@
 
 #include "chrome/browser/ui/views/toolbar/chrome_labs_button.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/about_flags.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
 #include "chrome/browser/ui/views/toolbar/chrome_labs_bubble_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "components/flags_ui/feature_entry_macros.h"
 #include "ui/events/event_utils.h"
 #include "ui/views/test/button_test_api.h"
 #include "ui/views/test/widget_test.h"
 
+namespace {
+const char kFirstTestFeatureId[] = "feature-1";
+}  // namespace
+
 class ChromeLabsButtonTest : public TestWithBrowserView {
  public:
   void SetUp() override {
@@ -28,6 +34,23 @@
   ChromeLabsButton* labs_button =
       browser_view()->toolbar()->chrome_labs_button();
   EXPECT_FALSE(ChromeLabsBubbleView::IsShowing());
+
+  // Explicitly set up the feature flags and LabInfo for the button instead of
+  // relying on ChromeLabsBubbleViewModel::SetUpLabs().
+  const base::Feature kTestFeature1{"FeatureName1",
+                                    base::FEATURE_ENABLED_BY_DEFAULT};
+
+  std::vector<flags_ui::FeatureEntry> entries = {
+      {kFirstTestFeatureId, "", "", flags_ui::FlagsState::GetCurrentPlatform(),
+       FEATURE_VALUE_TYPE(kTestFeature1)}};
+  about_flags::testing::SetFeatureEntries(entries);
+
+  std::vector<LabInfo> test_feature_info = {
+      {kFirstTestFeatureId, base::ASCIIToUTF16(""), base::ASCIIToUTF16(""),
+       version_info::Channel::STABLE}};
+
+  labs_button->SetLabInfoForTesting(test_feature_info);
+
   ui::MouseEvent e(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
                    ui::EventTimeForNow(), 0, 0);
   views::test::ButtonTestApi test_api(labs_button);
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc
index ac7be32..790072ff 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -34,7 +34,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/security_state/core/security_state.h"
 #include "components/url_formatter/url_formatter.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
diff --git a/chrome/browser/ui/web_applications/create_shortcut_browsertest.cc b/chrome/browser/ui/web_applications/create_shortcut_browsertest.cc
index 83e117e5..c041149 100644
--- a/chrome/browser/ui/web_applications/create_shortcut_browsertest.cc
+++ b/chrome/browser/ui/web_applications/create_shortcut_browsertest.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/web_applications/components/web_app_prefs_utils.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/browser/web_applications/test/web_app_install_observer.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
index f7406005..5134a2b 100644
--- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
+++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
@@ -38,7 +38,7 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
index 00acd376..37653229 100644
--- a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
+++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
@@ -23,7 +23,7 @@
 #include "chrome/browser/web_applications/components/web_app_utils.h"
 #include "chrome/browser/web_applications/components/web_application_info.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/navigation_entry.h"
 
 namespace web_app {
diff --git a/chrome/browser/ui/web_applications/web_app_metrics.cc b/chrome/browser/ui/web_applications/web_app_metrics.cc
index 22293d7..baec3270 100644
--- a/chrome/browser/ui/web_applications/web_app_metrics.cc
+++ b/chrome/browser/ui/web_applications/web_app_metrics.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "components/site_engagement/content/engagement_type.h"
 #include "components/site_engagement/content/site_engagement_service.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 
 using DisplayMode = blink::mojom::DisplayMode;
diff --git a/chrome/browser/ui/web_applications/web_app_metrics_browsertest.cc b/chrome/browser/ui/web_applications/web_app_metrics_browsertest.cc
index 81f169a..1877f60ccb 100644
--- a/chrome/browser/ui/web_applications/web_app_metrics_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_metrics_browsertest.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/daily_metrics_helper.h"
 #include "components/ukm/test_ukm_recorder.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.cc
index c21f11b..9d864efc 100644
--- a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.cc
@@ -19,6 +19,10 @@
 
 namespace {
 
+constexpr char kOptInVisibility[] = "optInVisibility";
+constexpr char kOptInDefaultState[] = "optInDefaultState";
+constexpr char kLegalFooterVisibility[] = "legalFooterVisibility";
+
 void RecordShowShelfNavigationButtonsValueChange(bool enabled) {
   base::UmaHistogramBoolean(
       "Accessibility.CrosShelfNavigationButtonsInTabletModeChanged.OOBE",
@@ -54,6 +58,8 @@
       IDS_LOGIN_MARKETING_OPT_IN_SCREEN_GET_CHROMEBOOK_UPDATES_SIGN_ME_UP);
   builder->Add("marketingOptInScreenAllSet",
                IDS_LOGIN_MARKETING_OPT_IN_SCREEN_ALL_SET);
+  builder->Add("marketingOptInScreenFooterNotice",
+               IDS_LOGIN_MARKETING_OPT_IN_SCREEN_FOOTER_NOTICE);
   builder->Add("marketingOptInA11yButtonLabel",
                IDS_MARKETING_OPT_IN_ACCESSIBILITY_BUTTON_LABEL);
   builder->Add("finalA11yPageTitle", IDS_MARKETING_OPT_IN_ACCESSIBILITY_TITLE);
@@ -71,8 +77,15 @@
   BaseScreenHandler::SetBaseScreen(screen);
 }
 
-void MarketingOptInScreenHandler::Show() {
-  ShowScreen(kScreenId);
+void MarketingOptInScreenHandler::Show(bool opt_in_visible,
+                                       bool opt_in_default_state,
+                                       bool legal_footer_visible) {
+  base::DictionaryValue data;
+  data.SetBoolean(kOptInVisibility, opt_in_visible);
+  data.SetBoolean(kOptInDefaultState, opt_in_default_state);
+  data.SetBoolean(kLegalFooterVisibility, legal_footer_visible);
+
+  ShowScreenWithData(kScreenId, &data);
 }
 
 void MarketingOptInScreenHandler::Hide() {
@@ -92,14 +105,6 @@
          enabled);
 }
 
-void MarketingOptInScreenHandler::SetOptInVisibility(bool visible) {
-  CallJS("login.MarketingOptInScreen.setOptInVisibility", visible);
-}
-
-void MarketingOptInScreenHandler::SetEmailToggleState(bool checked) {
-  CallJS("login.MarketingOptInScreen.setEmailToggleState", checked);
-}
-
 void MarketingOptInScreenHandler::Initialize() {}
 
 void MarketingOptInScreenHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
index a4898e6..84dbdb3e 100644
--- a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
@@ -25,7 +25,9 @@
   virtual void Bind(MarketingOptInScreen* screen) = 0;
 
   // Shows the contents of the screen.
-  virtual void Show() = 0;
+  virtual void Show(bool opt_in_visible,
+                    bool opt_in_default_state,
+                    bool legal_footer_visible) = 0;
 
   // Hides the contents of the screen.
   virtual void Hide() = 0;
@@ -33,15 +35,10 @@
   // Sets whether the a11y Settings button is visible.
   virtual void UpdateA11ySettingsButtonVisibility(bool shown) = 0;
 
-  // Sets whether the a11y setting for showing shelf navigation buttons is
+  // Sets whether the a11y setting for showing shelf navigation buttons is.
   // toggled on or off.
   virtual void UpdateA11yShelfNavigationButtonToggle(bool enabled) = 0;
 
-  // Sets the visibility of the marketing email opt-in
-  virtual void SetOptInVisibility(bool visible) = 0;
-
-  // Updates the toggle state for the email opt-in
-  virtual void SetEmailToggleState(bool checked) = 0;
 };
 
 // The sole implementation of the MarketingOptInScreenView, using WebUI.
@@ -59,12 +56,12 @@
 
   // MarketingOptInScreenView:
   void Bind(MarketingOptInScreen* screen) override;
-  void Show() override;
+  void Show(bool opt_in_visible,
+            bool opt_in_default_state,
+            bool legal_footer_visible) override;
   void Hide() override;
   void UpdateA11ySettingsButtonVisibility(bool shown) override;
   void UpdateA11yShelfNavigationButtonToggle(bool enabled) override;
-  void SetOptInVisibility(bool visible) override;
-  void SetEmailToggleState(bool checked) override;
 
  private:
   // BaseScreenHandler:
diff --git a/chrome/browser/ui/webui/invalidations/invalidations_message_handler.cc b/chrome/browser/ui/webui/invalidations/invalidations_message_handler.cc
index 9987d42a..a56c8de4 100644
--- a/chrome/browser/ui/webui/invalidations/invalidations_message_handler.cc
+++ b/chrome/browser/ui/webui/invalidations/invalidations_message_handler.cc
@@ -89,9 +89,9 @@
 }
 
 void InvalidationsMessageHandler::OnStateChange(
-    const syncer::InvalidatorState& new_state,
+    const invalidation::InvalidatorState& new_state,
     const base::Time& last_changed_timestamp) {
-  std::string state(syncer::InvalidatorStateToString(new_state));
+  std::string state(invalidation::InvalidatorStateToString(new_state));
   web_ui()->CallJavascriptFunctionUnsafe(
       "chrome.invalidations.updateInvalidatorState", base::Value(state),
       base::Value(last_changed_timestamp.ToJsTime()));
@@ -99,7 +99,7 @@
 
 void InvalidationsMessageHandler::OnUpdatedTopics(
     const std::string& handler_name,
-    const syncer::TopicCountMap& topics) {
+    const invalidation::TopicCountMap& topics) {
   base::ListValue list_of_objects;
   for (const auto& topic_item : topics) {
     std::unique_ptr<base::DictionaryValue> dic(new base::DictionaryValue());
@@ -120,7 +120,7 @@
     const base::DictionaryValue& details) {}
 
 void InvalidationsMessageHandler::OnInvalidation(
-    const syncer::TopicInvalidationMap& new_invalidations) {
+    const invalidation::TopicInvalidationMap& new_invalidations) {
   std::unique_ptr<base::ListValue> invalidations_list =
       new_invalidations.ToValue();
   web_ui()->CallJavascriptFunctionUnsafe(
diff --git a/chrome/browser/ui/webui/invalidations/invalidations_message_handler.h b/chrome/browser/ui/webui/invalidations/invalidations_message_handler.h
index b4d9b7c..7331887 100644
--- a/chrome/browser/ui/webui/invalidations/invalidations_message_handler.h
+++ b/chrome/browser/ui/webui/invalidations/invalidations_message_handler.h
@@ -30,13 +30,14 @@
   // Implementation of InvalidationLoggerObserver.
   void OnRegistrationChange(
       const std::multiset<std::string>& registered_handlers) override;
-  void OnStateChange(const syncer::InvalidatorState& new_state,
+  void OnStateChange(const invalidation::InvalidatorState& new_state,
                      const base::Time& last_change_timestamp) override;
-  void OnUpdatedTopics(const std::string& handler_name,
-                       const syncer::TopicCountMap& topics_counts) override;
+  void OnUpdatedTopics(
+      const std::string& handler_name,
+      const invalidation::TopicCountMap& topics_counts) override;
   void OnDebugMessage(const base::DictionaryValue& details) override;
   void OnInvalidation(
-      const syncer::TopicInvalidationMap& new_invalidations) override;
+      const invalidation::TopicInvalidationMap& new_invalidations) override;
   void OnDetailedStatus(const base::DictionaryValue& network_details) override;
 
   // Implementation of WebUIMessageHandler.
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 24f5201..52047a25 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -74,7 +74,7 @@
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_ui.h"
 #include "extensions/browser/app_sorting.h"
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/browser/ui/webui/settings/site_settings_helper.cc
index d01e50a..af39c45 100644
--- a/chrome/browser/ui/webui/settings/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_helper.cc
@@ -151,8 +151,8 @@
     {ContentSettingsType::DISPLAY_CAPTURE, nullptr},
 };
 
-// TODO(crbug.com/1149878): After removing ContentSettingsType::PLUGINS, remove
-// +1.
+// TODO(crbug.com/1149878): After removing
+// ContentSettingsType::DEPRECATED_PLUGINS, remove +1.
 static_assert(base::size(kContentSettingsTypeGroupNames) + 1 ==
                   // ContentSettingsType starts at -1, so add 1 here.
                   static_cast<int32_t>(ContentSettingsType::NUM_TYPES) + 1,
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
index 0432221..3f345d09 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/profile_picker.h"
 #include "chrome/browser/ui/signin/profile_colors_util.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/user_manager.h"
 #include "chrome/browser/ui/webui/profile_helper.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
@@ -446,6 +447,11 @@
       shortcut_manager->CreateProfileShortcut(profile->GetPath());
   }
 
+  if (base::FeatureList::IsEnabled(features::kSignInProfileCreation)) {
+    // Skip the FRE for this profile if sign-in was offered as part of the flow.
+    profile->GetPrefs()->SetBoolean(prefs::kHasSeenWelcomePage, true);
+  }
+
   RecordNewProfileSpec(profile_color, create_shortcut);
   // Launch profile and close the picker.
   profiles::OpenBrowserWindowForProfile(
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index a032df9..dc67418 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -92,7 +92,7 @@
     "//components/services/app_service/public/cpp:protocol_handling",
     "//components/sync",
     "//components/user_manager",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//content/public/browser",
     "//services/metrics/public/cpp:ukm_builders",
     "//skia",
@@ -226,7 +226,7 @@
     "//chrome/test:test_support",
     "//components/services/app_service/public/cpp:app_url_handling",
     "//components/services/app_service/public/cpp:protocol_handling",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//content/public/browser",
     "//content/test:test_support",
     "//services/metrics/public/cpp:ukm_builders",
@@ -288,7 +288,7 @@
     "//components/permissions:permissions",
     "//components/services/app_service/public/cpp:app_update",
     "//components/services/app_service/public/cpp:intents",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//extensions/browser:test_support",
   ]
 
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 469d08a..905f217 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -151,7 +151,7 @@
     "//components/services/app_service/public/mojom",
     "//components/site_engagement/core/mojom:mojo_bindings",
     "//components/user_manager:user_manager",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//content/public/browser",
     "//extensions/common:common_constants",
     "//net",
@@ -218,8 +218,8 @@
     "//chrome/browser/web_applications:web_applications_test_support",
     "//chrome/browser/web_applications/extensions:extensions",
     "//chrome/test:test_support",
-    "//components/webapps",
-    "//components/webapps:test_support",
+    "//components/webapps/browser",
+    "//components/webapps/browser:test_support",
     "//content/public/browser",
     "//services/preferences/public/cpp",
     "//skia",
diff --git a/chrome/browser/web_applications/components/install_bounce_metric.h b/chrome/browser/web_applications/components/install_bounce_metric.h
index 3d28ece3..c2c79ab 100644
--- a/chrome/browser/web_applications/components/install_bounce_metric.h
+++ b/chrome/browser/web_applications/components/install_bounce_metric.h
@@ -9,7 +9,7 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 
 class PrefService;
 class PrefRegistrySimple;
diff --git a/chrome/browser/web_applications/components/install_finalizer.h b/chrome/browser/web_applications/components/install_finalizer.h
index f8bdbd3..ee096fe 100644
--- a/chrome/browser/web_applications/components/install_finalizer.h
+++ b/chrome/browser/web_applications/components/install_finalizer.h
@@ -12,7 +12,7 @@
 #include "chrome/browser/web_applications/components/web_app_chromeos_data.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
 #include "chrome/browser/web_applications/components/web_app_system_web_app_data.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 
 struct WebApplicationInfo;
 class GURL;
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever.cc b/chrome/browser/web_applications/components/web_app_data_retriever.cc
index 994f8c0b..a0fd855 100644
--- a/chrome/browser/web_applications/components/web_app_data_retriever.cc
+++ b/chrome/browser/web_applications/components/web_app_data_retriever.cc
@@ -16,8 +16,8 @@
 #include "chrome/browser/web_applications/components/web_app_icon_generator.h"
 #include "chrome/browser/web_applications/components/web_application_info.h"
 #include "chrome/common/chrome_render_frame.mojom.h"
-#include "components/webapps/installable/installable_data.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
index ccbf09b..ba7f7c5d 100644
--- a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
+++ b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
@@ -18,10 +18,10 @@
 #include "chrome/common/web_page_metadata.mojom.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/webapps/installable/fake_installable_manager.h"
-#include "components/webapps/installable/installable_data.h"
-#include "components/webapps/installable/installable_manager.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/fake_installable_manager.h"
+#include "components/webapps/browser/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/web_applications/components/web_app_install_utils.cc b/chrome/browser/web_applications/components/web_app_install_utils.cc
index 0208cfa..189c1f8 100644
--- a/chrome/browser/web_applications/components/web_app_install_utils.cc
+++ b/chrome/browser/web_applications/components/web_app_install_utils.cc
@@ -22,8 +22,8 @@
 #include "chrome/browser/web_applications/components/web_application_info.h"
 #include "chrome/common/chrome_features.h"
 #include "components/services/app_service/public/cpp/share_target.h"
-#include "components/webapps/installable/installable_data.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
diff --git a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
index 237654a..533bd170 100644
--- a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
+++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -39,7 +39,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/url_loader_interceptor.h"
diff --git a/chrome/browser/web_applications/manifest_update_task.cc b/chrome/browser/web_applications/manifest_update_task.cc
index e70b22bf..719642b 100644
--- a/chrome/browser/web_applications/manifest_update_task.cc
+++ b/chrome/browser/web_applications/manifest_update_task.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/components/web_application_info.h"
 #include "chrome/common/chrome_features.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/common/content_features.h"
 #include "ui/gfx/skia_util.h"
 
diff --git a/chrome/browser/web_applications/pending_app_install_task.cc b/chrome/browser/web_applications/pending_app_install_task.cc
index e1bee1cc..29fe541 100644
--- a/chrome/browser/web_applications/pending_app_install_task.cc
+++ b/chrome/browser/web_applications/pending_app_install_task.cc
@@ -20,9 +20,9 @@
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/components/web_application_info.h"
-#include "components/webapps/installable/installable_manager.h"
-#include "components/webapps/installable/installable_metrics.h"
-#include "components/webapps/installable/installable_params.h"
+#include "components/webapps/browser/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_params.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace web_app {
diff --git a/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc b/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
index b538ab1..1a672d1 100644
--- a/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager_browsertest.cc
@@ -22,7 +22,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index 37dbf42..89ebafda 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -32,7 +32,7 @@
 #include "chrome/browser/web_applications/web_app_installation_utils.h"
 #include "chrome/browser/web_applications/web_app_registry_update.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/skia/include/core/SkColor.h"
 
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc
index a383a15..4d5560c 100644
--- a/chrome/browser/web_applications/web_app_install_manager.cc
+++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/web_applications/components/web_application_info.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_install_task.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/web_contents.h"
 
 namespace web_app {
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc
index 9437afc..8a9edad 100644
--- a/chrome/browser/web_applications/web_app_install_task.cc
+++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -29,8 +29,8 @@
 #include "chrome/browser/web_applications/components/web_app_utils.h"
 #include "chrome/browser/web_applications/components/web_application_info.h"
 #include "chrome/common/chrome_features.h"
-#include "components/webapps/installable/installable_manager.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
diff --git a/chrome/browser/web_applications/web_app_install_task.h b/chrome/browser/web_applications/web_app_install_task.h
index e62b329..679ad5e 100644
--- a/chrome/browser/web_applications/web_app_install_task.h
+++ b/chrome/browser/web_applications/web_app_install_task.h
@@ -19,7 +19,7 @@
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
 #include "chrome/browser/web_applications/components/web_app_url_loader.h"
 #include "chrome/browser/web_applications/components/web_application_info.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/web_contents_observer.h"
 
 class GURL;
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 54664e6e..b35f205 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -47,8 +47,8 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "components/webapps/installable/installable_data.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/web_applications/web_app_migration_manager_browsertest.cc b/chrome/browser/web_applications/web_app_migration_manager_browsertest.cc
index bf50c08..57e7ad4 100644
--- a/chrome/browser/web_applications/web_app_migration_manager_browsertest.cc
+++ b/chrome/browser/web_applications/web_app_migration_manager_browsertest.cc
@@ -35,7 +35,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_launcher.h"
 #include "content/public/test/url_loader_interceptor.h"
diff --git a/chrome/browser/web_applications/web_app_mover.cc b/chrome/browser/web_applications/web_app_mover.cc
index 7b6841f..5f999596 100644
--- a/chrome/browser/web_applications/web_app_mover.cc
+++ b/chrome/browser/web_applications/web_app_mover.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/web_applications/components/install_finalizer.h"
 #include "chrome/browser/web_applications/components/install_manager.h"
 #include "chrome/common/chrome_features.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/web_contents.h"
 
 namespace {
@@ -263,4 +263,4 @@
   }
 }
 
-}  // namespace web_app
\ No newline at end of file
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_mover_browsertest.cc b/chrome/browser/web_applications/web_app_mover_browsertest.cc
index 2548acf..777b03bf 100644
--- a/chrome/browser/web_applications/web_app_mover_browsertest.cc
+++ b/chrome/browser/web_applications/web_app_mover_browsertest.cc
@@ -16,7 +16,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/test/browser_test.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/webapps/android/BUILD.gn b/chrome/browser/webapps/android/BUILD.gn
index 0c5451f1..4c83a43 100644
--- a/chrome/browser/webapps/android/BUILD.gn
+++ b/chrome/browser/webapps/android/BUILD.gn
@@ -17,7 +17,7 @@
     "//base",
     "//chrome/browser/webapps/android:jni_headers",
     "//components/url_formatter:url_formatter",
-    "//components/webapps:webapps",
+    "//components/webapps/browser",
     "//content/public/browser:browser",
     "//services/device/public/mojom",
     "//skia",
diff --git a/chrome/browser/webapps/android/pwa_bottom_sheet_controller.h b/chrome/browser/webapps/android/pwa_bottom_sheet_controller.h
index 78b879f..04e749a 100644
--- a/chrome/browser/webapps/android/pwa_bottom_sheet_controller.h
+++ b/chrome/browser/webapps/android/pwa_bottom_sheet_controller.h
@@ -10,7 +10,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "components/webapps/android/installable/installable_ambient_badge_infobar_delegate.h"
+#include "components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/webapps/chrome_webapps_client.cc b/chrome/browser/webapps/chrome_webapps_client.cc
index a6c1aae..7160cb0 100644
--- a/chrome/browser/webapps/chrome_webapps_client.cc
+++ b/chrome/browser/webapps/chrome_webapps_client.cc
@@ -7,7 +7,7 @@
 #include "base/logging.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/web_contents.h"
 
 #if defined(OS_ANDROID)
@@ -17,7 +17,7 @@
 #include "chrome/browser/feature_engagement/tracker_factory.h"
 #include "components/feature_engagement/public/event_constants.h"
 #include "components/feature_engagement/public/tracker.h"
-#include "components/webapps/android/add_to_homescreen_params.h"
+#include "components/webapps/browser/android/add_to_homescreen_params.h"
 #endif
 
 namespace webapps {
diff --git a/chrome/browser/webapps/chrome_webapps_client.h b/chrome/browser/webapps/chrome_webapps_client.h
index f5fc305c..004433e 100644
--- a/chrome/browser/webapps/chrome_webapps_client.h
+++ b/chrome/browser/webapps/chrome_webapps_client.h
@@ -7,7 +7,7 @@
 
 #include "base/no_destructor.h"
 #include "build/build_config.h"
-#include "components/webapps/webapps_client.h"
+#include "components/webapps/browser/webapps_client.h"
 
 namespace webapps {
 
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 6124f62..724fbda 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1610431066-b046cf295bac84ed9eefc440cb75a6df945c21fe.profdata
+chrome-linux-master-1610452567-fdff272b709a6fb84edf0325fafb43e63f345a7e.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index ffd6067..136543f13 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1610431066-5d7d40ce59ba8e505b376b46e02fe57205cb3e46.profdata
+chrome-mac-master-1610452567-9a68a195870106cae6c4ac4841f20ff7b185cdf9.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 724313c..e100ab3 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1610420273-f729673981a14d4f8cc70d6513013e1d16474c41.profdata
+chrome-win32-master-1610452567-971e6bfbeacac133e734933b87972f0e8c85e431.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index cd7d99d..7aa58eb2 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1610431066-60b154442ebb054827e182b9c834d6f36e05d2b3.profdata
+chrome-win64-master-1610463436-2052566ba20716214eb6d7caa0887c28794c37bd.profdata
diff --git a/chrome/common/extensions/api/omnibox.json b/chrome/common/extensions/api/omnibox.json
index 59cb7aa..22a4168 100644
--- a/chrome/common/extensions/api/omnibox.json
+++ b/chrome/common/extensions/api/omnibox.json
@@ -116,6 +116,17 @@
         }
       }
     ],
+    "manifest_keys": {
+      "omnibox": {
+        "type": "object",
+        "properties": {
+          "keyword": {
+            "type": "string",
+            "description": "The keyword to register with the omnibox. Must be non-empty."
+          }
+        }
+      }
+    },
     "functions": [
       {
         "name": "sendSuggestions",
diff --git a/chrome/common/extensions/api/omnibox/omnibox_handler.cc b/chrome/common/extensions/api/omnibox/omnibox_handler.cc
index 52c5569..060ed01 100644
--- a/chrome/common/extensions/api/omnibox/omnibox_handler.cc
+++ b/chrome/common/extensions/api/omnibox/omnibox_handler.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "chrome/common/extensions/api/omnibox.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
@@ -17,15 +18,14 @@
 
 namespace {
 
-// Manifest keys.
-const char kKeyword[] = "keyword";
+using ManifestKeys = api::omnibox::ManifestKeys;
 
 }  // namespace
 
 // static
 const std::string& OmniboxInfo::GetKeyword(const Extension* extension) {
   OmniboxInfo* info = static_cast<OmniboxInfo*>(
-      extension->GetManifestData(manifest_keys::kOmnibox));
+      extension->GetManifestData(ManifestKeys::kOmnibox));
   return info ? info->keyword : base::EmptyString();
 }
 
@@ -36,21 +36,25 @@
 }
 
 bool OmniboxHandler::Parse(Extension* extension, base::string16* error) {
-  std::unique_ptr<OmniboxInfo> info(new OmniboxInfo);
-  const base::DictionaryValue* dict = NULL;
-  if (!extension->manifest()->GetDictionary(manifest_keys::kOmnibox,
-                                            &dict) ||
-      !dict->GetString(kKeyword, &info->keyword) ||
-      info->keyword.empty()) {
-    *error = base::ASCIIToUTF16(manifest_errors::kInvalidOmniboxKeyword);
+  ManifestKeys manifest_keys;
+  if (!ManifestKeys::ParseFromDictionary(*extension->manifest()->value(),
+                                         &manifest_keys, error)) {
     return false;
   }
-  extension->SetManifestData(manifest_keys::kOmnibox, std::move(info));
+
+  auto info = std::make_unique<OmniboxInfo>();
+  info->keyword = manifest_keys.omnibox.keyword;
+  if (info->keyword.empty()) {
+    *error = base::ASCIIToUTF16(manifest_errors::kEmptyOmniboxKeyword);
+    return false;
+  }
+
+  extension->SetManifestData(ManifestKeys::kOmnibox, std::move(info));
   return true;
 }
 
 base::span<const char* const> OmniboxHandler::Keys() const {
-  static constexpr const char* kKeys[] = {manifest_keys::kOmnibox};
+  static constexpr const char* kKeys[] = {ManifestKeys::kOmnibox};
   return kKeys;
 }
 
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 6a1a6f3..4699dc42 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2273,17 +2273,6 @@
 // A string pref with initial locale set in VPD or manifest.
 const char kInitialLocale[] = "intl.initial_locale";
 
-// A boolean pref of the OOBE complete flag (first OOBE part before login).
-const char kOobeComplete[] = "OobeComplete";
-
-// The name of the screen that has to be shown if OOBE has been interrupted.
-const char kOobeScreenPending[] = "OobeScreenPending";
-
-// A boolean pref to indicate if the marketing opt-in screen in OOBE is finished
-// for the user.
-const char kOobeMarketingOptInScreenFinished[] =
-    "OobeMarketingOptInScreenFinished";
-
 // A boolean pref of the device registered flag (second part after first login).
 const char kDeviceRegistered[] = "DeviceRegistered";
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index dfbb36e91..cf90fdc 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -723,9 +723,6 @@
 extern const char kEchoCheckedOffers[];
 extern const char kCachedMultiProfileUserBehavior[];
 extern const char kInitialLocale[];
-extern const char kOobeComplete[];
-extern const char kOobeScreenPending[];
-extern const char kOobeMarketingOptInScreenFinished[];
 extern const char kDeviceRegistered[];
 extern const char kEnrollmentRecoveryRequired[];
 extern const char kHelpAppShouldShowGetStarted[];
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index fea876e..b5b5090 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -87,7 +87,6 @@
 #include "components/error_page/common/localized_error.h"
 #include "components/grit/components_scaled_resources.h"
 #include "components/network_hints/renderer/web_prescient_networking_impl.h"
-#include "components/no_state_prefetch/common/prerender_types.mojom.h"
 #include "components/no_state_prefetch/common/prerender_url_loader_throttle.h"
 #include "components/no_state_prefetch/renderer/no_state_prefetch_client.h"
 #include "components/no_state_prefetch/renderer/prerender_helper.h"
@@ -1309,10 +1308,8 @@
 }
 
 bool ChromeContentRendererClient::IsPrefetchOnly(
-    content::RenderFrame* render_frame,
-    const blink::WebURLRequest& request) {
-  return prerender::PrerenderHelper::GetPrerenderMode(render_frame) ==
-         prerender::mojom::PrerenderMode::kPrefetchOnly;
+    content::RenderFrame* render_frame) {
+  return prerender::PrerenderHelper::IsPrerendering(render_frame);
 }
 
 uint64_t ChromeContentRendererClient::VisitedLinkHash(const char* canonical_url,
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index 857b350..30718f6 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -130,8 +130,7 @@
                        const net::SiteForCookies& site_for_cookies,
                        const url::Origin* initiator_origin,
                        GURL* new_url) override;
-  bool IsPrefetchOnly(content::RenderFrame* render_frame,
-                      const blink::WebURLRequest& request) override;
+  bool IsPrefetchOnly(content::RenderFrame* render_frame) override;
   uint64_t VisitedLinkHash(const char* canonical_url, size_t length) override;
   bool IsLinkVisited(uint64_t link_hash) override;
   std::unique_ptr<blink::WebPrescientNetworking> CreatePrescientNetworking(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index d6004b2..7af02fa0 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -472,7 +472,7 @@
       "//build:chromeos_buildflags",
       "//chrome/browser/web_applications:web_applications_on_extensions_test_support",
       "//chrome/browser/web_applications:web_applications_test_support",
-      "//components/webapps",
+      "//components/webapps/browser",
     ]
     allow_circular_includes_from = [
       "//chrome/browser/web_applications:web_applications_on_extensions_test_support",
@@ -3576,7 +3576,6 @@
     "../browser/notifications/platform_notification_service_unittest.cc",
     "../browser/optimization_guide/optimization_guide_hints_manager_unittest.cc",
     "../browser/optimization_guide/optimization_guide_navigation_data_unittest.cc",
-    "../browser/optimization_guide/optimization_guide_permissions_util_unittest.cc",
     "../browser/optimization_guide/optimization_guide_top_host_provider_unittest.cc",
     "../browser/optimization_guide/prediction/prediction_manager_unittest.cc",
     "../browser/optimization_guide/prediction/prediction_model_download_manager_unittest.cc",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index ca8ee52..7895556 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -301,7 +301,7 @@
     "//components/signin/public/android:java",
     "//components/sync/android:sync_java",
     "//components/translate/content/android:java",
-    "//components/webapps/android:java",
+    "//components/webapps/browser/android:java",
     "//content/public/android:content_java",
     "//content/public/test/android:content_java_test_support",
     "//net/android:net_java",
diff --git a/chrome/test/data/downloads/page_with_canvas_image.html b/chrome/test/data/downloads/page_with_canvas_image.html
new file mode 100644
index 0000000..23d2ef40
--- /dev/null
+++ b/chrome/test/data/downloads/page_with_canvas_image.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<head>
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<canvas id="canvas" width="300" height="300" style="border:1px solid #000000;"></canvas>
+<script>
+var c = document.getElementById("canvas");
+var ctx = c.getContext("2d");
+ctx.beginPath();
+ctx.moveTo(0, 0);
+ctx.lineTo(300, 300);
+ctx.stroke();
+</script>
+</body>
+</html>
diff --git a/chrome/test/data/pdf/metrics_test.js b/chrome/test/data/pdf/metrics_test.js
index e157ed7..b03f194 100644
--- a/chrome/test/data/pdf/metrics_test.js
+++ b/chrome/test/data/pdf/metrics_test.js
@@ -250,5 +250,35 @@
           chrome.metricsPrivate.actionCounter);
       chrome.test.succeed();
     },
+
+    function testMetricsOverflowMenu() {
+      PDFMetrics.resetForTesting();
+
+      chrome.metricsPrivate = new MockMetricsPrivate();
+      PDFMetrics.record(UserAction.DOCUMENT_OPENED);
+
+      PDFMetrics.record(UserAction.TOGGLE_DISPLAY_ANNOTATIONS);
+      PDFMetrics.record(UserAction.PRESENT);
+      PDFMetrics.record(UserAction.PROPERTIES);
+      PDFMetrics.record(UserAction.PRESENT);
+      PDFMetrics.record(UserAction.PRESENT);
+      PDFMetrics.record(UserAction.PROPERTIES);
+      PDFMetrics.record(UserAction.TOGGLE_DISPLAY_ANNOTATIONS);
+      PDFMetrics.record(UserAction.PROPERTIES);
+      PDFMetrics.record(UserAction.PRESENT);
+
+      chrome.test.assertEq(
+          {
+            [UserAction.DOCUMENT_OPENED]: 1,
+            [UserAction.TOGGLE_DISPLAY_ANNOTATIONS_FIRST]: 1,
+            [UserAction.TOGGLE_DISPLAY_ANNOTATIONS]: 2,
+            [UserAction.PRESENT_FIRST]: 1,
+            [UserAction.PRESENT]: 4,
+            [UserAction.PROPERTIES_FIRST]: 1,
+            [UserAction.PROPERTIES]: 3,
+          },
+          chrome.metricsPrivate.actionCounter);
+      chrome.test.succeed();
+    },
   ];
 }());
diff --git a/chrome/test/data/pdf/viewer_properties_dialog_test.js b/chrome/test/data/pdf/viewer_properties_dialog_test.js
index b175a8a..f177425 100644
--- a/chrome/test/data/pdf/viewer_properties_dialog_test.js
+++ b/chrome/test/data/pdf/viewer_properties_dialog_test.js
@@ -50,7 +50,7 @@
 
     // TODO(crbug.com/93169): None of the following expected values should be
     // '-' when support for every property is implemented.
-    [['file-name', '-'],
+    [['file-name', 'document_info.pdf'],
      ['file-size', '-'],
      ['title', 'Sample PDF Document Info'],
      ['author', 'Chromium Authors'],
@@ -61,9 +61,9 @@
      ['application', 'Your Preferred Text Editor'],
      ['pdf-producer', 'fixup_pdf_template.py'],
      ['pdf-version', '1.7'],
-     ['page-count', '-'],
+     ['page-count', '1'],
      ['page-size', '-'],
-     ['fast-web-view', '-'],
+     ['fast-web-view', 'No'],
     ].forEach(([field, expectedValue]) => assertField(field, expectedValue));
 
     await ensurePropertiesDialogClose();
diff --git a/chrome/test/data/webui/chromeos/scanning/scanner_select_test.js b/chrome/test/data/webui/chromeos/scanning/scanner_select_test.js
index f0531ef..32e2960 100644
--- a/chrome/test/data/webui/chromeos/scanning/scanner_select_test.js
+++ b/chrome/test/data/webui/chromeos/scanning/scanner_select_test.js
@@ -66,7 +66,9 @@
     assertFalse(select.hidden);
     assertTrue(throbber.hidden);
     assertTrue(helpLink.hidden);
-    assertEquals(2, select.length);
+    // The expected options are the 2 scanners + the hidden 'No scanners'
+    // option.
+    assertEquals(3, select.length);
     assertEquals(firstScannerName, select.options[0].textContent.trim());
     assertEquals(secondScannerName, select.options[1].textContent.trim());
     assertEquals(tokenToString(firstScannerId), select.value);
diff --git a/chrome/test/data/webui/chromeos/scanning/source_select_test.js b/chrome/test/data/webui/chromeos/scanning/source_select_test.js
index a07edf5..d9a6141 100644
--- a/chrome/test/data/webui/chromeos/scanning/source_select_test.js
+++ b/chrome/test/data/webui/chromeos/scanning/source_select_test.js
@@ -48,11 +48,12 @@
   });
 
   test('initializeSourceSelect', () => {
-    // Before options are added, the dropdown should be enabled and empty.
+    // Before options are added, the dropdown should be enabled and display the
+    // default option.
     const select = sourceSelect.$$('select');
     assertTrue(!!select);
     assertFalse(select.disabled);
-    assertEquals(0, select.length);
+    assertEquals(1, select.length);
 
     const firstSource =
         createScannerSource(SourceType.ADF_SIMPLEX, 'adf simplex', pageSizes);
@@ -63,8 +64,9 @@
     flush();
 
     // Verify that adding sources results in the dropdown displaying the correct
-    // options.
-    assertEquals(2, select.length);
+    // options. The expected options are simplex, flatbed, and the hidden
+    // default option.
+    assertEquals(3, select.length);
     assertEquals(
         getSourceTypeString(firstSource.type),
         select.options[0].textContent.trim());
diff --git a/chrome/test/data/webui/resources/list_property_update_behavior_tests.js b/chrome/test/data/webui/resources/list_property_update_behavior_tests.js
index a11be43..8b571cd 100644
--- a/chrome/test/data/webui/resources/list_property_update_behavior_tests.js
+++ b/chrome/test/data/webui/resources/list_property_update_behavior_tests.js
@@ -4,7 +4,7 @@
 
 /** @fileoverview Suite of tests for the ListPropertyUpdateBehavior.  */
 
-// #import {ListPropertyUpdateBehavior, updateListProperty} from 'chrome://resources/js/list_property_update_behavior.m.js';
+// #import {ListPropertyUpdateBehavior} from 'chrome://resources/js/list_property_update_behavior.m.js';
 // #import {Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 suite('ListPropertyUpdateBehavior', function() {
@@ -76,7 +76,7 @@
       updateComplexArray(newArray) {
         if (this.updateList(
                 'complexArray', x => x.letter, newArray,
-                true /* identityBasedUpdate */)) {
+                true /* uidBasedUpdate */)) {
           return {topArrayChanged: true, wordsArrayChanged: false};
         }
 
@@ -305,48 +305,4 @@
     assertTrue(testElement.updateList('complexArray', x => x.letter, newArray));
     assertDeepEquals(['apricot'], testElement.complexArray[0].words);
   });
-
-  test('updateListProperty() function triggers notifySplices()', () => {
-    // Ensure that the array is updated when an element is removed from the
-    // end.
-    let elementRemoved = testElement.complexArray.slice(0, 2);
-    updateListProperty(
-        testElement, 'complexArray', obj => obj, elementRemoved, true);
-    assertComplexArrayEquals(testElement.complexArray, elementRemoved);
-
-    // Ensure that the array is updated when an element is removed from the
-    // beginning.
-    testElement.resetComplexArray();
-    elementRemoved = testElement.complexArray.slice(1);
-    updateListProperty(
-        testElement, 'complexArray', obj => obj, elementRemoved, true);
-    assertComplexArrayEquals(testElement.complexArray, elementRemoved);
-
-    // Ensure that the array is updated when an element is added to the end.
-    testElement.resetComplexArray();
-    let elementAdded = testElement.complexArray.slice();
-    elementAdded.push({letter: 'd', words: ['door', 'dice']});
-    updateListProperty(
-        testElement, 'complexArray', obj => obj, elementAdded, true);
-    assertComplexArrayEquals(testElement.complexArray, elementAdded);
-
-    // Ensure that the array is updated when an element is added to the
-    // beginning.
-    testElement.resetComplexArray();
-    elementAdded = [{letter: 'A', words: ['Alphabet']}];
-    elementAdded.push(...testElement.complexArray);
-    updateListProperty(
-        testElement, 'complexArray', obj => obj, elementAdded, true);
-    assertComplexArrayEquals(testElement.complexArray, elementAdded);
-
-    // Ensure that the array is updated when the entire array is different.
-    testElement.resetComplexArray();
-    const newArray = [
-      {letter: 'w', words: ['water', 'woods']},
-      {letter: 'x', words: ['xylophone']}, {letter: 'y', words: ['yo-yo']},
-      {letter: 'z', words: ['zebra', 'zephyr']}
-    ];
-    updateListProperty(testElement, 'complexArray', obj => obj, newArray, true);
-    assertComplexArrayEquals(testElement.complexArray, newArray);
-  });
 });
diff --git a/chrome/test/data/webui/tab_search/infinite_list_test.js b/chrome/test/data/webui/tab_search/infinite_list_test.js
index e704262..f924aed 100644
--- a/chrome/test/data/webui/tab_search/infinite_list_test.js
+++ b/chrome/test/data/webui/tab_search/infinite_list_test.js
@@ -87,7 +87,6 @@
   test('ScrollHeight', async () => {
     const tabItems = sampleTabItems(sampleSiteNames());
     await setupTest(tabItems);
-    await waitAfterNextRender(infiniteList);
 
     assertEquals(0, infiniteList.scrollTop);
 
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_app.html b/chromeos/components/diagnostics_ui/resources/diagnostics_app.html
index 41d3325..43b4ae5 100644
--- a/chromeos/components/diagnostics_ui/resources/diagnostics_app.html
+++ b/chromeos/components/diagnostics_ui/resources/diagnostics_app.html
@@ -43,7 +43,7 @@
     padding: 5px;
   }
 </style>
-<div id="diagnosticsContainer">
+<div id="diagnosticsContainer" hidden="[[!systemInfoReceived_]]">
   <div id="header">[[i18n('diagnosticsTitle')]]</div>
   <div class="overview-container">
     <overview-card id="overviewCard"></overview-card>
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_app.js b/chromeos/components/diagnostics_ui/resources/diagnostics_app.js
index de6210c0..d5592f6 100644
--- a/chromeos/components/diagnostics_ui/resources/diagnostics_app.js
+++ b/chromeos/components/diagnostics_ui/resources/diagnostics_app.js
@@ -46,6 +46,12 @@
       type: Boolean,
       value: false,
     },
+
+    /** @type {boolean} */
+    systemInfoReceived_: {
+      type: Boolean,
+      value: false,
+    },
   },
 
   /** @override */
@@ -66,6 +72,7 @@
    * @private
    */
   onSystemInfoReceived_(systemInfo) {
+    this.systemInfoReceived_ = true;
     this.showBatteryStatusCard_ = systemInfo.deviceCapabilities.hasBattery;
   },
 
diff --git a/chromeos/components/scanning/resources/scanner_select.html b/chromeos/components/scanning/resources/scanner_select.html
index 36c8e5e..35f8de9 100644
--- a/chromeos/components/scanning/resources/scanner_select.html
+++ b/chromeos/components/scanning/resources/scanner_select.html
@@ -20,18 +20,14 @@
     <select id="scannerSelect" class="md-select"
         value="{{selectedScannerId::change}}" hidden$="[[!loaded]]"
         disabled="[[disabled]]" aria-labelledby="scannerLabel">
-      <!-- TODO(jschettler): Figure out why hiding/disabling the option doesn't
-          remove it from the dropdown. -->
-      <template is="dom-if" if="[[!scanners.length]]" restamp>
-        <option value="">
-          [[i18n('noScannersText')]]
-        </option>
-      </template>
       <template is="dom-repeat" items="[[scanners]]" as="scanner">
         <option value="[[getTokenAsString_(scanner)]]">
           [[getScannerDisplayName_(scanner)]]
         </option>
       </template>
+      <option value="" hidden="[[scanners.length]]">
+        [[i18n('noScannersText')]]
+      </option>
     </select>
   </div>
   <div id="scanHelp" slot="error"
diff --git a/chromeos/components/scanning/resources/source_select.html b/chromeos/components/scanning/resources/source_select.html
index 27d8775..8add52b 100644
--- a/chromeos/components/scanning/resources/source_select.html
+++ b/chromeos/components/scanning/resources/source_select.html
@@ -7,17 +7,15 @@
     <select id="sourceSelect" class="md-select"
         value="{{selectedSource::change}}" disabled="[[disabled]]"
         aria-labelledby="sourceLabel">
-      <template is="dom-if" if="[[!sources.length]]" restamp>
-        <option value="">
-          [[i18n('defaultSourceOptionText')]]
-        </option>
-      </template>
       <template is="dom-repeat" items="[[sources]]" as="source">
         <option value="[[source.name]]"
             selected$='[[isDefaultSource_(source.type)]]'>
           [[getSourceTypeString_(source.type)]]
         </option>
       </template>
+      <option value="" hidden="[[sources.length]]">
+        [[i18n('defaultSourceOptionText')]]
+      </option>
     </select>
   </div>
 </scan-settings-section>
diff --git a/chromeos/services/tts/tts_service.cc b/chromeos/services/tts/tts_service.cc
index 3c56c398..25abdb68 100644
--- a/chromeos/services/tts/tts_service.cc
+++ b/chromeos/services/tts/tts_service.cc
@@ -22,7 +22,9 @@
 }  // namespace
 
 TtsService::TtsService(mojo::PendingReceiver<mojom::TtsService> receiver)
-    : service_receiver_(this, std::move(receiver)), tts_stream_factory_(this) {
+    : service_receiver_(this, std::move(receiver)),
+      tts_stream_factory_(this),
+      task_runner_(base::ThreadTaskRunnerHandle::Get()) {
   if (setpriority(PRIO_PROCESS, 0, -10 /* real time audio */) != 0) {
     PLOG(ERROR) << "Unable to request real time priority; performance will be "
                    "impacted.";
@@ -122,7 +124,6 @@
                        int prior_frames_skipped,
                        media::AudioBus* dest) {
   size_t frames_in_buf = 0;
-  int32_t status = -1;
   {
     base::AutoLock al(state_lock_);
     if (buffers_.empty())
@@ -130,34 +131,6 @@
 
     const AudioBuffer& buf = buffers_.front();
 
-    status = buf.status;
-    // Done, 0, or error, -1.
-    if (status <= 0) {
-      if (status == -1)
-        tts_event_observer_->OnError();
-      else
-        tts_event_observer_->OnEnd();
-
-      StopLocked();
-      return 0;
-    }
-
-    if (buf.is_first_buffer) {
-      start_playback_time_ = base::Time::Now();
-      tts_event_observer_->OnStart();
-    }
-
-    // Implicit timepoint.
-    if (buf.char_index != -1)
-      tts_event_observer_->OnTimepoint(buf.char_index);
-
-    // Explicit timepoint(s).
-    base::TimeDelta start_to_now = base::Time::Now() - start_playback_time_;
-    while (!timepoints_.empty() && timepoints_.front().second <= start_to_now) {
-      tts_event_observer_->OnTimepoint(timepoints_.front().first);
-      timepoints_.pop();
-    }
-
     frames_in_buf = buf.frames.size();
     const float* frames = nullptr;
     if (!buf.frames.empty())
@@ -165,7 +138,16 @@
     float* channel = dest->channel(0);
     for (size_t i = 0; i < frames_in_buf; i++)
       channel[i] = frames[i];
+
+    rendered_buffers_.push(std::move(buffers_.front()));
     buffers_.pop();
+
+    if (!process_rendered_buffers_posted_) {
+      process_rendered_buffers_posted_ = true;
+      task_runner_->PostTask(FROM_HERE,
+                             base::BindOnce(&TtsService::ProcessRenderedBuffers,
+                                            weak_factory_.GetWeakPtr()));
+    }
   }
 
   return frames_in_buf;
@@ -175,6 +157,7 @@
 
 void TtsService::StopLocked(bool clear_buffers) {
   output_device_->Pause();
+  rendered_buffers_ = std::queue<AudioBuffer>();
   if (clear_buffers) {
     buffers_ = std::queue<AudioBuffer>();
     timepoints_ = std::queue<Timepoint>();
@@ -191,6 +174,41 @@
   tts_stream_factory_.Bind(std::move(factory));
 }
 
+void TtsService::ProcessRenderedBuffers() {
+  base::AutoLock al(state_lock_);
+  process_rendered_buffers_posted_ = false;
+  for (; !rendered_buffers_.empty(); rendered_buffers_.pop()) {
+    const auto& buf = rendered_buffers_.front();
+    int status = buf.status;
+    // Done, 0, or error, -1.
+    if (status <= 0) {
+      if (status == -1)
+        tts_event_observer_->OnError();
+      else
+        tts_event_observer_->OnEnd();
+
+      StopLocked();
+      return;
+    }
+
+    if (buf.is_first_buffer) {
+      start_playback_time_ = base::Time::Now();
+      tts_event_observer_->OnStart();
+    }
+
+    // Implicit timepoint.
+    if (buf.char_index != -1)
+      tts_event_observer_->OnTimepoint(buf.char_index);
+  }
+
+  // Explicit timepoint(s).
+  base::TimeDelta start_to_now = base::Time::Now() - start_playback_time_;
+  while (!timepoints_.empty() && timepoints_.front().second <= start_to_now) {
+    tts_event_observer_->OnTimepoint(timepoints_.front().first);
+    timepoints_.pop();
+  }
+}
+
 TtsService::AudioBuffer::AudioBuffer() = default;
 
 TtsService::AudioBuffer::~AudioBuffer() = default;
diff --git a/chromeos/services/tts/tts_service.h b/chromeos/services/tts/tts_service.h
index 3c945ccf..0f62fd15 100644
--- a/chromeos/services/tts/tts_service.h
+++ b/chromeos/services/tts/tts_service.h
@@ -92,6 +92,10 @@
   // Satisfies any pending tts stream factory receivers.
   void ProcessPendingTtsStreamFactories();
 
+  // Do any processing (e.g. sending start/end events) on buffers that have just
+  // been rendered on the audio thread.
+  void ProcessRenderedBuffers();
+
   // Connection to tts in the browser.
   mojo::Receiver<mojom::TtsService> service_receiver_;
 
@@ -117,6 +121,7 @@
 
   // The queue of audio buffers to be played by the audio thread.
   std::queue<AudioBuffer> buffers_ GUARDED_BY(state_lock_);
+  std::queue<AudioBuffer> rendered_buffers_;
 
   // An explicit list of increasing time delta sorted timepoints to be fired
   // while rendering audio at the specified |delay| from start of audio
@@ -126,6 +131,14 @@
 
   // The time at which playback of the current utterance started.
   base::Time start_playback_time_;
+
+  // Whether a task to process rendered audio buffers has been posted.
+  bool process_rendered_buffers_posted_ GUARDED_BY(state_lock_) = false;
+
+  // The main thread's task runner handle.
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  base::WeakPtrFactory<TtsService> weak_factory_{this};
 };
 
 }  // namespace tts
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 0aea246..91fb415 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -312,7 +312,7 @@
       "//components/visitedlink/test:unit_tests",
       "//components/web_cache/browser:unit_tests",
       "//components/web_package:unit_tests",
-      "//components/webapps:unit_tests",
+      "//components/webapps/browser:unit_tests",
       "//components/webcrypto:unit_tests",
       "//components/webrtc_logging/browser:unit_tests",
       "//components/webrtc_logging/common:unit_tests",
@@ -374,8 +374,8 @@
       "//components/signin/public/android:java",
       "//components/spellcheck/browser/android:java",
       "//components/variations/android:variations_java",
-      "//components/webapps/android:java",
-      "//components/webapps/android:unit_tests",
+      "//components/webapps/browser/android:java",
+      "//components/webapps/browser/android:unit_tests",
       "//content/public/android:content_java",
       "//content/public/browser",
       "//net",
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc
index 6b996ae..5412207 100644
--- a/components/autofill/core/browser/autofill_test_utils.cc
+++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -875,26 +875,22 @@
 
 std::string NextMonth() {
   base::Time::Exploded now;
-  // Using AutofillClock here might cause test flakiness. See crbug/1108232.
-  base::Time::Now().LocalExplode(&now);
+  AutofillClock::Now().LocalExplode(&now);
   return base::StringPrintf("%02d", now.month % 12 + 1);
 }
 std::string LastYear() {
   base::Time::Exploded now;
-  // Using AutofillClock here might cause test flakiness. See crbug/1108232.
-  base::Time::Now().LocalExplode(&now);
+  AutofillClock::Now().LocalExplode(&now);
   return base::NumberToString(now.year - 1);
 }
 std::string NextYear() {
   base::Time::Exploded now;
-  // Using AutofillClock here might cause test flakiness. See crbug/1108232.
-  base::Time::Now().LocalExplode(&now);
+  AutofillClock::Now().LocalExplode(&now);
   return base::NumberToString(now.year + 1);
 }
 std::string TenYearsFromNow() {
   base::Time::Exploded now;
-  // Using AutofillClock here might cause test flakiness. See crbug/1108232.
-  base::Time::Now().LocalExplode(&now);
+  AutofillClock::Now().LocalExplode(&now);
   return base::NumberToString(now.year + 10);
 }
 
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index deba417..a7bc8ddbf 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -342,7 +342,13 @@
 
   // Sets or updates contextual information.
   // Passing nullptr clears the contextual information.
-  virtual void SetDetails(std::unique_ptr<Details> details) = 0;
+  virtual void SetDetails(std::unique_ptr<Details> details,
+                          base::TimeDelta delay) = 0;
+
+  // Append |details| to the current contextual information.
+  // Passing nullptr does nothing.
+  virtual void AppendDetails(std::unique_ptr<Details> details,
+                             base::TimeDelta delay) = 0;
 
   // Clears the info box.
   virtual void ClearInfoBox() = 0;
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index 5a28613..c35b389 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -235,7 +235,10 @@
   MOCK_CONST_METHOD0(GetWebController, WebController*());
   MOCK_METHOD0(GetEmailAddressForAccessTokenAccount, std::string());
   MOCK_METHOD0(GetLocale, std::string());
-  MOCK_METHOD1(SetDetails, void(std::unique_ptr<Details> details));
+  MOCK_METHOD2(SetDetails,
+               void(std::unique_ptr<Details> details, base::TimeDelta delay));
+  MOCK_METHOD2(AppendDetails,
+               void(std::unique_ptr<Details> details, base::TimeDelta delay));
   MOCK_METHOD1(SetInfoBox, void(const InfoBox& info_box));
   MOCK_METHOD0(ClearInfoBox, void());
   MOCK_METHOD1(SetProgress, void(int progress));
diff --git a/components/autofill_assistant/browser/actions/show_details_action.cc b/components/autofill_assistant/browser/actions/show_details_action.cc
index ea08e6e9..d6f7f83 100644
--- a/components/autofill_assistant/browser/actions/show_details_action.cc
+++ b/components/autofill_assistant/browser/actions/show_details_action.cc
@@ -60,7 +60,13 @@
     VLOG(1) << "Failed to fill the details";
     UpdateProcessedAction(INVALID_ACTION);
   } else {
-    delegate_->SetDetails(std::move(details));
+    base::TimeDelta delay =
+        base::TimeDelta::FromMilliseconds(proto_.show_details().delay_ms());
+    if (proto_.show_details().append()) {
+      delegate_->AppendDetails(std::move(details), delay);
+    } else {
+      delegate_->SetDetails(std::move(details), delay);
+    }
     UpdateProcessedAction(ACTION_APPLIED);
   }
 
diff --git a/components/autofill_assistant/browser/actions/show_details_action_unittest.cc b/components/autofill_assistant/browser/actions/show_details_action_unittest.cc
index 8b5576b9..dfb40e0 100644
--- a/components/autofill_assistant/browser/actions/show_details_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/show_details_action_unittest.cc
@@ -28,7 +28,7 @@
   void SetUp() override {
     autofill::CountryNames::SetLocaleString("us-en");
 
-    ON_CALL(mock_action_delegate_, SetDetails(_)).WillByDefault(Return());
+    ON_CALL(mock_action_delegate_, SetDetails(_, _)).WillByDefault(Return());
     ON_CALL(mock_action_delegate_, GetUserData)
         .WillByDefault(Return(&user_data_));
     ON_CALL(mock_action_delegate_, GetLastSuccessfulUserDataOptions)
@@ -64,7 +64,7 @@
 };
 
 TEST_F(ShowDetailsActionTest, EmptyIsValid) {
-  EXPECT_CALL(mock_action_delegate_, SetDetails(_));
+  EXPECT_CALL(mock_action_delegate_, SetDetails(_, _));
   EXPECT_CALL(
       callback_,
       Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
@@ -74,7 +74,7 @@
 TEST_F(ShowDetailsActionTest, DetailsCase) {
   proto_.mutable_details();
 
-  EXPECT_CALL(mock_action_delegate_, SetDetails(_));
+  EXPECT_CALL(mock_action_delegate_, SetDetails(_, _));
   EXPECT_CALL(
       callback_,
       Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
@@ -86,7 +86,7 @@
   user_data_.selected_addresses_["contact"] = MakeAutofillProfile();
   user_data_options_.request_payer_name = true;
 
-  EXPECT_CALL(mock_action_delegate_, SetDetails(_));
+  EXPECT_CALL(mock_action_delegate_, SetDetails(_, _));
   EXPECT_CALL(
       callback_,
       Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
@@ -97,7 +97,7 @@
   proto_.set_shipping_address("shipping");
   user_data_.selected_addresses_["shipping"] = MakeAutofillProfile();
 
-  EXPECT_CALL(mock_action_delegate_, SetDetails(_));
+  EXPECT_CALL(mock_action_delegate_, SetDetails(_, _));
   EXPECT_CALL(
       callback_,
       Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
@@ -108,7 +108,7 @@
   proto_.set_credit_card(true);
   user_data_.selected_card_ = MakeCreditCard();
 
-  EXPECT_CALL(mock_action_delegate_, SetDetails(_));
+  EXPECT_CALL(mock_action_delegate_, SetDetails(_, _));
   EXPECT_CALL(
       callback_,
       Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
@@ -117,7 +117,7 @@
 
 TEST_F(ShowDetailsActionTest, CreditCardRequestedButNotAvailable) {
   proto_.set_credit_card(true);
-  EXPECT_CALL(mock_action_delegate_, SetDetails(_)).Times(0);
+  EXPECT_CALL(mock_action_delegate_, SetDetails(_, _)).Times(0);
   EXPECT_CALL(
       callback_,
       Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 84511c13..d54e5c61 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -114,6 +114,30 @@
   user_model_.RemoveObserver(this);
 }
 
+Controller::DetailsHolder::DetailsHolder(
+    std::unique_ptr<Details> details,
+    std::unique_ptr<base::OneShotTimer> timer)
+    : details_(std::move(details)), timer_(std::move(timer)) {}
+
+Controller::DetailsHolder::~DetailsHolder() = default;
+Controller::DetailsHolder::DetailsHolder(DetailsHolder&& other) = default;
+Controller::DetailsHolder& Controller::DetailsHolder::operator=(
+    DetailsHolder&& other) = default;
+
+const Details& Controller::DetailsHolder::GetDetails() const {
+  return *details_;
+}
+
+bool Controller::DetailsHolder::CurrentlyVisible() const {
+  // If there is a timer associated to these details, then they should be shown
+  // only once the timer has triggered.
+  return !timer_;
+}
+
+void Controller::DetailsHolder::Enable() {
+  timer_.reset();
+}
+
 const ClientSettings& Controller::GetSettings() {
   return settings_;
 }
@@ -203,15 +227,69 @@
   return bubble_message_;
 }
 
-void Controller::SetDetails(std::unique_ptr<Details> details) {
-  details_ = std::move(details);
-  for (ControllerObserver& observer : observers_) {
-    observer.OnDetailsChanged(details_.get());
+void Controller::SetDetails(std::unique_ptr<Details> details,
+                            base::TimeDelta delay) {
+  details_.clear();
+
+  // There is nothing to append: notify that we cleared the details and return.
+  if (!details) {
+    NotifyDetailsChanged();
+    return;
+  }
+
+  // If there is a delay, notify now that details have been cleared. If there is
+  // no delay, AppendDetails will take care of the notifying the observers after
+  // appending the details.
+  if (!delay.is_zero()) {
+    NotifyDetailsChanged();
+  }
+
+  AppendDetails(std::move(details), delay);
+}
+
+void Controller::AppendDetails(std::unique_ptr<Details> details,
+                               base::TimeDelta delay) {
+  if (!details) {
+    return;
+  }
+
+  if (delay.is_zero()) {
+    details_.push_back(DetailsHolder(std::move(details), /* timer= */ nullptr));
+    NotifyDetailsChanged();
+    return;
+  }
+
+  // Delay the addition of the new details.
+  size_t details_index = details_.size();
+  auto timer = std::make_unique<base::OneShotTimer>();
+  timer->Start(FROM_HERE, delay,
+               base::BindOnce(&Controller::MakeDetailsVisible,
+                              weak_ptr_factory_.GetWeakPtr(), details_index));
+  details_.push_back(DetailsHolder(std::move(details), std::move(timer)));
+}
+
+void Controller::MakeDetailsVisible(size_t details_index) {
+  if (details_index < details_.size()) {
+    details_[details_index].Enable();
+    NotifyDetailsChanged();
   }
 }
 
-const Details* Controller::GetDetails() const {
-  return details_.get();
+void Controller::NotifyDetailsChanged() {
+  std::vector<Details> details = GetDetails();
+  for (ControllerObserver& observer : observers_) {
+    observer.OnDetailsChanged(details);
+  }
+}
+
+std::vector<Details> Controller::GetDetails() const {
+  std::vector<Details> details;
+  for (const auto& holder : details_) {
+    if (holder.CurrentlyVisible()) {
+      details.push_back(holder.GetDetails());
+    }
+  }
+  return details;
 }
 
 int Controller::GetProgress() const {
@@ -735,7 +813,7 @@
     script_tracker_->StopScript();
 
   ClearInfoBox();
-  SetDetails(nullptr);
+  SetDetails(nullptr, base::TimeDelta());
   SetUserActions(nullptr);
   SetCollectUserDataOptions(nullptr);
   SetForm(nullptr, base::DoNothing(), base::DoNothing());
@@ -1103,7 +1181,7 @@
 void Controller::InitFromParameters() {
   auto details = std::make_unique<Details>();
   if (details->UpdateFromParameters(*trigger_context_))
-    SetDetails(std::move(details));
+    SetDetails(std::move(details), base::TimeDelta());
 
   const base::Optional<std::string> overlay_color =
       trigger_context_->GetOverlayColors();
@@ -1252,8 +1330,11 @@
   }
   dict.SetKey("scripts", script_tracker()->GetDebugContext());
 
-  if (details_)
-    dict.SetKey("details", details_->GetDebugContext());
+  std::vector<base::Value> details_list;
+  for (const auto& holder : details_) {
+    details_list.push_back(holder.GetDetails().GetDebugContext());
+  }
+  dict.SetKey("details", base::Value(details_list));
 
   std::string output_js;
   base::JSONWriter::Write(dict, &output_js);
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index a4b8d7f..219c2ec 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -120,7 +120,9 @@
   std::string GetStatusMessage() const override;
   void SetBubbleMessage(const std::string& message) override;
   std::string GetBubbleMessage() const override;
-  void SetDetails(std::unique_ptr<Details> details) override;
+  void SetDetails(std::unique_ptr<Details>, base::TimeDelta delay) override;
+  void AppendDetails(std::unique_ptr<Details> details,
+                     base::TimeDelta delay) override;
   void SetInfoBox(const InfoBox& info_box) override;
   void ClearInfoBox() override;
   void SetProgress(int progress) override;
@@ -186,7 +188,7 @@
   // Overrides autofill_assistant::UiDelegate:
   AutofillAssistantState GetState() const override;
   void OnUserInteractionInsideTouchableArea() override;
-  const Details* GetDetails() const override;
+  std::vector<Details> GetDetails() const override;
   const InfoBox* GetInfoBox() const override;
   int GetProgress() const override;
   base::Optional<int> GetProgressActiveStep() const override;
@@ -260,6 +262,34 @@
  private:
   friend ControllerTest;
 
+  // A holder class which contains some details and, optionally, a timer that
+  // will "enable" them later on.
+  class DetailsHolder {
+   public:
+    DetailsHolder(std::unique_ptr<Details> details,
+                  std::unique_ptr<base::OneShotTimer> timer);
+    ~DetailsHolder();
+    DetailsHolder(DetailsHolder&& other);
+    DetailsHolder& operator=(DetailsHolder&& other);
+
+    // The details held by this object.
+    const Details& GetDetails() const;
+
+    // Whether the details held by this object are visible. Will return false if
+    // a timer was set and was not reached yet.
+    bool CurrentlyVisible() const;
+
+    // Enable the details held by this object so that they are shown (i.e.
+    // CurrentlyVisible() returns true).
+    //
+    // In practice, this is called at most once when |timer_| is triggered.
+    void Enable();
+
+   private:
+    std::unique_ptr<Details> details_;
+    std::unique_ptr<base::OneShotTimer> timer_;
+  };
+
   void SetWebControllerForTest(std::unique_ptr<WebController> web_controller);
 
   // Called when the committed URL has or might have changed.
@@ -361,6 +391,9 @@
 
   void SetVisibilityAndUpdateUserActions();
 
+  void MakeDetailsVisible(size_t details_index);
+  void NotifyDetailsChanged();
+
   ClientSettings settings_;
   Client* const client_;
   const base::TickClock* const tick_clock_;
@@ -416,8 +449,8 @@
   // Current bubble / tooltip message, may be empty.
   std::string bubble_message_;
 
-  // Current details, may be null.
-  std::unique_ptr<Details> details_;
+  // Current details, may be empty.
+  std::vector<DetailsHolder> details_;
 
   // Current info box, may be null.
   std::unique_ptr<InfoBox> info_box_;
diff --git a/components/autofill_assistant/browser/controller_observer.h b/components/autofill_assistant/browser/controller_observer.h
index 6847274..e99dda4 100644
--- a/components/autofill_assistant/browser/controller_observer.h
+++ b/components/autofill_assistant/browser/controller_observer.h
@@ -55,9 +55,9 @@
   virtual void OnUserDataChanged(const UserData* state,
                                  UserData::FieldChange field_change) = 0;
 
-  // Called when details have changed. Details will be null if they have been
+  // Called when details have changed. Details will be empty if they have been
   // cleared.
-  virtual void OnDetailsChanged(const Details* details) = 0;
+  virtual void OnDetailsChanged(const std::vector<Details>& details) = 0;
 
   // Called when info box has changed. |info_box| will be null if it has been
   // cleared.
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 9269398..0f7cdabdf 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -2955,4 +2955,65 @@
   Start();
   EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
 }
+
+TEST_F(ControllerTest, Details) {
+  // The current controller details, as notified to the observers.
+  std::vector<Details> observed_details;
+
+  ON_CALL(mock_observer_, OnDetailsChanged(_))
+      .WillByDefault(
+          Invoke([&observed_details](const std::vector<Details>& details) {
+            observed_details = details;
+          }));
+
+  // Details are initially empty.
+  EXPECT_THAT(controller_->GetDetails(), IsEmpty());
+
+  // Set 2 details.
+  controller_->SetDetails(std::make_unique<Details>(), base::TimeDelta());
+  EXPECT_THAT(controller_->GetDetails(), SizeIs(1));
+  EXPECT_THAT(observed_details, SizeIs(1));
+
+  // Set 2 details in 1s (which directly clears the current details).
+  controller_->SetDetails(std::make_unique<Details>(),
+                          base::TimeDelta::FromMilliseconds(1000));
+  EXPECT_THAT(controller_->GetDetails(), IsEmpty());
+  EXPECT_THAT(observed_details, IsEmpty());
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
+  EXPECT_THAT(controller_->GetDetails(), SizeIs(1));
+  EXPECT_THAT(observed_details, SizeIs(1));
+
+  controller_->AppendDetails(std::make_unique<Details>(),
+                             /* delay= */ base::TimeDelta());
+  EXPECT_THAT(controller_->GetDetails(), SizeIs(2));
+  EXPECT_THAT(observed_details, SizeIs(2));
+
+  // Delay the appending of the details.
+  controller_->AppendDetails(
+      std::make_unique<Details>(),
+      /* delay= */ base::TimeDelta::FromMilliseconds(1000));
+  EXPECT_THAT(controller_->GetDetails(), SizeIs(2));
+  EXPECT_THAT(observed_details, SizeIs(2));
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromMilliseconds(999));
+  EXPECT_THAT(controller_->GetDetails(), SizeIs(2));
+  EXPECT_THAT(observed_details, SizeIs(2));
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+  EXPECT_THAT(controller_->GetDetails(), SizeIs(3));
+  EXPECT_THAT(observed_details, SizeIs(3));
+
+  // Setting the details clears the timers.
+  controller_->AppendDetails(
+      std::make_unique<Details>(),
+      /* delay= */ base::TimeDelta::FromMilliseconds(1000));
+  controller_->SetDetails(nullptr, base::TimeDelta());
+  EXPECT_THAT(controller_->GetDetails(), IsEmpty());
+  EXPECT_THAT(observed_details, IsEmpty());
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromMilliseconds(2000));
+  EXPECT_THAT(controller_->GetDetails(), IsEmpty());
+  EXPECT_THAT(observed_details, IsEmpty());
+}
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/details.cc b/components/autofill_assistant/browser/details.cc
index bf5ba0c..04c70c6 100644
--- a/components/autofill_assistant/browser/details.cc
+++ b/components/autofill_assistant/browser/details.cc
@@ -89,6 +89,10 @@
 
 Details::Details() = default;
 Details::~Details() = default;
+Details::Details(Details&& other) = default;
+Details& Details::operator=(Details&& other) = default;
+Details::Details(const Details& other) = default;
+Details& Details::operator=(const Details& other) = default;
 
 // static
 bool Details::UpdateFromProto(const ShowDetailsProto& proto, Details* details) {
diff --git a/components/autofill_assistant/browser/details.h b/components/autofill_assistant/browser/details.h
index c43a7f5..7c098d6e 100644
--- a/components/autofill_assistant/browser/details.h
+++ b/components/autofill_assistant/browser/details.h
@@ -20,6 +20,12 @@
   Details();
   ~Details();
 
+  // Details is movable and copyable.
+  Details(Details&& other);
+  Details& operator=(Details&& other);
+  Details(const Details& other);
+  Details& operator=(const Details& other);
+
   // Returns a dictionary describing the current execution context, which
   // is intended to be serialized as JSON string. The execution context is
   // useful when analyzing feedback forms and for debugging in general.
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index 824fe9e..5ae3812 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -93,8 +93,22 @@
   return status_message_;
 }
 
-void FakeScriptExecutorDelegate::SetDetails(std::unique_ptr<Details> details) {
-  details_ = std::move(details);
+void FakeScriptExecutorDelegate::SetDetails(std::unique_ptr<Details> details,
+                                            base::TimeDelta delay) {
+  // We ignore |delay|.
+  if (details) {
+    details_ = {*details};
+  } else {
+    details_ = {};
+  }
+}
+
+void FakeScriptExecutorDelegate::AppendDetails(std::unique_ptr<Details> details,
+                                               base::TimeDelta delay) {
+  // We ignore |delay|.
+  if (details) {
+    details_.push_back(*details);
+  }
 }
 
 void FakeScriptExecutorDelegate::SetInfoBox(const InfoBox& info_box) {
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.h b/components/autofill_assistant/browser/fake_script_executor_delegate.h
index 3d2bce60..a5a4409 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -43,7 +43,10 @@
   std::string GetStatusMessage() const override;
   void SetBubbleMessage(const std::string& message) override;
   std::string GetBubbleMessage() const override;
-  void SetDetails(std::unique_ptr<Details> details) override;
+  void SetDetails(std::unique_ptr<Details> details,
+                  base::TimeDelta delay) override;
+  void AppendDetails(std::unique_ptr<Details> details,
+                     base::TimeDelta delay) override;
   void SetInfoBox(const InfoBox& info_box) override;
   void ClearInfoBox() override;
   void SetProgress(int progress) override;
@@ -126,7 +129,7 @@
                                   : state_history_.back();
   }
 
-  Details* GetDetails() { return details_.get(); }
+  const std::vector<Details>& GetDetails() { return details_; }
 
   InfoBox* GetInfoBox() { return info_box_.get(); }
 
@@ -158,7 +161,7 @@
   std::unique_ptr<TriggerContext> trigger_context_;
   std::vector<AutofillAssistantState> state_history_;
   std::string status_message_;
-  std::unique_ptr<Details> details_;
+  std::vector<Details> details_;
   std::unique_ptr<InfoBox> info_box_;
   std::unique_ptr<std::vector<UserAction>> user_actions_;
   std::unique_ptr<CollectUserDataOptions> last_payment_request_options_;
diff --git a/components/autofill_assistant/browser/mock_controller_observer.h b/components/autofill_assistant/browser/mock_controller_observer.h
index cad2c44..6db59a1b 100644
--- a/components/autofill_assistant/browser/mock_controller_observer.h
+++ b/components/autofill_assistant/browser/mock_controller_observer.h
@@ -34,7 +34,7 @@
   MOCK_METHOD2(OnUserDataChanged,
                void(const UserData* user_data,
                     UserData::FieldChange field_change));
-  MOCK_METHOD1(OnDetailsChanged, void(const Details* details));
+  MOCK_METHOD1(OnDetailsChanged, void(const std::vector<Details>& details));
   MOCK_METHOD1(OnInfoBoxChanged, void(const InfoBox* info_box));
   MOCK_METHOD1(OnProgressChanged, void(int progress));
   MOCK_METHOD1(OnProgressActiveStepChanged, void(int active_step));
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 80910397..daf2f2a 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -247,7 +247,7 @@
   }
 
   delegate_->ClearInfoBox();
-  delegate_->SetDetails(nullptr);
+  delegate_->SetDetails(nullptr, base::TimeDelta());
   delegate_->SetCollectUserDataOptions(nullptr);
   delegate_->SetForm(nullptr, base::DoNothing(), base::DoNothing());
 
@@ -747,8 +747,14 @@
   return delegate_->GetLocale();
 }
 
-void ScriptExecutor::SetDetails(std::unique_ptr<Details> details) {
-  return delegate_->SetDetails(std::move(details));
+void ScriptExecutor::SetDetails(std::unique_ptr<Details> details,
+                                base::TimeDelta delay) {
+  return delegate_->SetDetails(std::move(details), delay);
+}
+
+void ScriptExecutor::AppendDetails(std::unique_ptr<Details> details,
+                                   base::TimeDelta delay) {
+  return delegate_->AppendDetails(std::move(details), delay);
 }
 
 void ScriptExecutor::ClearInfoBox() {
@@ -895,7 +901,7 @@
 
 void ScriptExecutor::RunCallback(bool success) {
   if (should_clean_contextual_ui_on_finish_ || !success) {
-    SetDetails(nullptr);
+    SetDetails(nullptr, base::TimeDelta());
     should_clean_contextual_ui_on_finish_ = false;
   }
 
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index ab6e678c..79bd45c 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -236,7 +236,10 @@
   WebController* GetWebController() const override;
   std::string GetEmailAddressForAccessTokenAccount() override;
   std::string GetLocale() override;
-  void SetDetails(std::unique_ptr<Details> details) override;
+  void SetDetails(std::unique_ptr<Details> details,
+                  base::TimeDelta delay) override;
+  void AppendDetails(std::unique_ptr<Details> details,
+                     base::TimeDelta delay) override;
   void ClearInfoBox() override;
   void SetInfoBox(const InfoBox& info_box) override;
   void SetProgress(int progress) override;
diff --git a/components/autofill_assistant/browser/script_executor_delegate.h b/components/autofill_assistant/browser/script_executor_delegate.h
index 24ab4b2..78dc335 100644
--- a/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/components/autofill_assistant/browser/script_executor_delegate.h
@@ -82,7 +82,10 @@
   virtual std::string GetStatusMessage() const = 0;
   virtual void SetBubbleMessage(const std::string& message) = 0;
   virtual std::string GetBubbleMessage() const = 0;
-  virtual void SetDetails(std::unique_ptr<Details> details) = 0;
+  virtual void SetDetails(std::unique_ptr<Details> details,
+                          base::TimeDelta delay) = 0;
+  virtual void AppendDetails(std::unique_ptr<Details> details,
+                             base::TimeDelta delay) = 0;
   virtual void SetInfoBox(const InfoBox& info_box) = 0;
   virtual void ClearInfoBox() = 0;
   virtual void SetCollectUserDataOptions(
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index c33dfa2..7a86d49 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -380,9 +380,10 @@
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
 
-  delegate_.SetDetails(std::make_unique<Details>());  // empty, but not null
+  // empty, but not null
+  delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
   executor_->Run(&user_data_, executor_callback_.Get());
-  EXPECT_EQ(nullptr, delegate_.GetDetails());
+  EXPECT_THAT(delegate_.GetDetails(), IsEmpty());
 }
 
 TEST_F(ScriptExecutorTest, DontClearDetailsIfOtherActionsAreLeft) {
@@ -400,9 +401,10 @@
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
 
-  delegate_.SetDetails(std::make_unique<Details>());  // empty, but not null
+  // empty, but not null
+  delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
   executor_->Run(&user_data_, executor_callback_.Get());
-  EXPECT_NE(nullptr, delegate_.GetDetails());
+  EXPECT_THAT(delegate_.GetDetails(), Not(IsEmpty()));
 }
 
 TEST_F(ScriptExecutorTest, ClearDetailsOnError) {
@@ -414,9 +416,11 @@
       .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, false)));
-  delegate_.SetDetails(std::make_unique<Details>());  // empty, but not null
+
+  // empty, but not null
+  delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
   executor_->Run(&user_data_, executor_callback_.Get());
-  EXPECT_EQ(nullptr, delegate_.GetDetails());
+  EXPECT_THAT(delegate_.GetDetails(), IsEmpty());
 }
 
 TEST_F(ScriptExecutorTest, UpdateScriptStateWhileRunning) {
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index d5fdfc9..0748f4c 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -2361,6 +2361,19 @@
   // Flags indicating which parts of the details (if any) have changed.
   // This field is taken into account only if |details| is filled.
   optional DetailsChangesProto change_flags = 2;
+
+  // Whether the details should be added/appended instead of replacing the
+  // current details.
+  optional bool append = 6;
+
+  // If set, add a delay of |delay_ms| before setting/appending the details.
+  //
+  // The details will never be shown if another ShowDetailsProto action with
+  // |append| = false is sent after this action and before the delay is reached.
+  //
+  // Note that it's not possible to delay the clearing of the details. If
+  // |data_to_show| is not set, then the details will be cleared directly.
+  optional bool delay_ms = 7;
 }
 
 // Set the value of an form element.
diff --git a/components/autofill_assistant/browser/ui_delegate.h b/components/autofill_assistant/browser/ui_delegate.h
index c276031..7d5c3155 100644
--- a/components/autofill_assistant/browser/ui_delegate.h
+++ b/components/autofill_assistant/browser/ui_delegate.h
@@ -57,8 +57,8 @@
   // Returns the current bubble / tooltip message.
   virtual std::string GetBubbleMessage() const = 0;
 
-  // Returns the current contextual information. May be null if empty.
-  virtual const Details* GetDetails() const = 0;
+  // Returns the current contextual information. May be empty.
+  virtual std::vector<Details> GetDetails() const = 0;
 
   // Returns the current info box data. May be null if empty.
   virtual const InfoBox* GetInfoBox() const = 0;
diff --git a/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc b/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
index 5611c9d..6fc8c69 100644
--- a/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
+++ b/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
@@ -22,6 +22,7 @@
 #include "components/content_settings/browser/test_page_specific_content_settings_delegate.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
+#include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
@@ -47,13 +48,31 @@
     "ContentSettings.Popups.StrongBlocker.NumBlocked";
 
 class SafeBrowsingTriggeredPopupBlockerTest
-    : public content::RenderViewHostTestHarness {
+    : public content::RenderViewHostTestHarness,
+      public subresource_filter::SubresourceFilterClient {
  public:
   SafeBrowsingTriggeredPopupBlockerTest() = default;
   ~SafeBrowsingTriggeredPopupBlockerTest() override {
     settings_map_->ShutdownOnUIThread();
   }
 
+  // subresource_filter::SubresourceFilterClient:
+  void ShowNotification() override {}
+  subresource_filter::mojom::ActivationLevel OnPageActivationComputed(
+      content::NavigationHandle* navigation_handle,
+      subresource_filter::mojom::ActivationLevel initial_activation_level,
+      subresource_filter::ActivationDecision* decision) override {
+    return initial_activation_level;
+  }
+  void OnAdsViolationTriggered(
+      content::RenderFrameHost*,
+      subresource_filter::mojom::AdsViolation) override {}
+  const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
+  GetSafeBrowsingDatabaseManager() override {
+    return nullptr;
+  }
+  void OnReloadRequested() override {}
+
   // content::RenderViewHostTestHarness:
   void SetUp() override {
     content::RenderViewHostTestHarness::SetUp();
@@ -142,7 +161,7 @@
       content::NavigationHandle* handle) {
     return std::make_unique<
         subresource_filter::SubresourceFilterSafeBrowsingActivationThrottle>(
-        handle, /*delegate=*/nullptr, content::GetIOThreadTaskRunner({}),
+        handle, this, content::GetIOThreadTaskRunner({}),
         fake_safe_browsing_database_);
   }
 
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
index 5a761e7..74530d4 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -682,12 +682,16 @@
             return;
         }
         if (requestCode == REQUEST_CODE_NOTIFICATION_CHANNEL_SETTINGS) {
+            @ContentSettingValues
+            int newPermission =
+                    mSite.getContentSetting(getSiteSettingsDelegate().getBrowserContextHandle(),
+                            ContentSettingsType.NOTIFICATIONS);
             // User has navigated back from system channel settings on O+. Ensure notification
             // preference is up to date, since they might have toggled it from channel settings.
             Preference notificationsPreference =
                     findPreference(getPreferenceKey(ContentSettingsType.NOTIFICATIONS));
             if (notificationsPreference != null) {
-                setUpNotificationsPreference(notificationsPreference, false /* isEmbargoed */);
+                onPreferenceChange(notificationsPreference, (Object) newPermission);
             }
 
             // To ensure UMA receives notification revocations, we detect if the setting has changed
@@ -695,10 +699,6 @@
             // permission, but do not return immediately to Chrome (e.g. they close the permissions
             // activity, instead of hitting the back button), but prevents us from having to check
             // for changes each time Chrome becomes active.
-            @ContentSettingValues
-            int newPermission =
-                    mSite.getContentSetting(getSiteSettingsDelegate().getBrowserContextHandle(),
-                            ContentSettingsType.NOTIFICATIONS);
             if (mPreviousNotificationPermission == ContentSettingValues.ALLOW
                     && newPermission != ContentSettingValues.ALLOW) {
                 WebsitePreferenceBridgeJni.get().reportNotificationRevokedForOrigin(
@@ -936,10 +936,10 @@
             preference.setIcon(getContentSettingsIcon(contentType, value, true));
         }
 
-        preference.setOrder(++mMaxPermissionOrder);
         // These preferences are persisted elsewhere, using SharedPreferences
-        //  can cause issues with keys matching up with value.
+        // can cause issues with keys matching up with value.
         preference.setPersistent(false);
+        preference.setOrder(++mMaxPermissionOrder);
         getPreferenceScreen().addPreference(preference);
     }
 
@@ -1117,11 +1117,14 @@
 
         @ContentSettingValues
         int permission;
-        if (preference instanceof ListPreference) {
-            permission = ContentSetting.fromString((String) newValue);
-        } else {
+        if (newValue instanceof Boolean) {
             permission =
                     (Boolean) newValue ? ContentSettingValues.ALLOW : ContentSettingValues.BLOCK;
+            // TODO(crbug.com/1165765): Remove when ListPreferences are no longer used.
+        } else if (newValue instanceof String) {
+            permission = ContentSetting.fromString((String) newValue);
+        } else {
+            permission = (Integer) newValue;
         }
 
         mSite.setContentSetting(browserContextHandle, type, permission);
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc
index a02db37..b76c341 100644
--- a/components/content_settings/core/common/content_settings.cc
+++ b/components/content_settings/core/common/content_settings.cc
@@ -32,7 +32,7 @@
     {ContentSettingsType::COOKIES, 0},
     {ContentSettingsType::IMAGES, 1},
     {ContentSettingsType::JAVASCRIPT, 2},
-    {ContentSettingsType::PLUGINS, 3},
+    {ContentSettingsType::DEPRECATED_PLUGINS, 3},
     {ContentSettingsType::POPUPS, 4},
     {ContentSettingsType::GEOLOCATION, 5},
     {ContentSettingsType::NOTIFICATIONS, 6},
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h
index e641fcb8..a7ea788 100644
--- a/components/content_settings/core/common/content_settings_types.h
+++ b/components/content_settings/core/common/content_settings_types.h
@@ -21,7 +21,7 @@
   COOKIES = 0,
   IMAGES,
   JAVASCRIPT,
-  PLUGINS,
+  DEPRECATED_PLUGINS,
 
   // This setting governs both popups and unwanted redirects like tab-unders and
   // framebusting.
diff --git a/components/data_reduction_proxy/core/browser/BUILD.gn b/components/data_reduction_proxy/core/browser/BUILD.gn
index ce05c74b..95fe82a 100644
--- a/components/data_reduction_proxy/core/browser/BUILD.gn
+++ b/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -47,7 +47,6 @@
       "//components/previews/core:core",
       "//components/variations",
       "//components/variations/net",
-      "//content/public/browser",
       "//crypto",
       "//google_apis",
       "//net:net",
@@ -81,7 +80,6 @@
     "//components/previews/core:core",
     "//components/variations",
     "//components/variations/net",
-    "//content/public/browser",
     "//crypto",
     "//google_apis",
     "//net",
@@ -173,8 +171,6 @@
     "//components/prefs:test_support",
     "//components/previews/core",
     "//components/variations",
-    "//content/public/browser",
-    "//content/test:test_support",
     "//net:test_support",
     "//services/network:network_service",
     "//services/network:test_support",
diff --git a/components/data_reduction_proxy/core/browser/DEPS b/components/data_reduction_proxy/core/browser/DEPS
index 63e2976..367a20af 100644
--- a/components/data_reduction_proxy/core/browser/DEPS
+++ b/components/data_reduction_proxy/core/browser/DEPS
@@ -4,6 +4,4 @@
   "+services/network/public",
   "+services/network/test",
   "+third_party/leveldatabase",
-  "+content/public/browser",
-  "+content/public/test",
 ]
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc
index 2a13a6d..790e445 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/task_environment.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
@@ -24,7 +25,6 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
 #include "net/proxy_resolution/proxy_info.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -52,10 +52,8 @@
 
   PrefService* prefs() { return &prefs_; }
 
- protected:
-  content::BrowserTaskEnvironment task_environment_;
-
  private:
+  base::test::TaskEnvironment task_environment_;
   TestingPrefServiceSimple prefs_;
 };
 
diff --git a/components/drive/drive_notification_manager.cc b/components/drive/drive_notification_manager.cc
index 0bafc65c..30958d2 100644
--- a/components/drive/drive_notification_manager.cc
+++ b/components/drive/drive_notification_manager.cc
@@ -70,9 +70,9 @@
 }
 
 void DriveNotificationManager::OnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
+    invalidation::InvalidatorState state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  push_notification_enabled_ = (state == syncer::INVALIDATIONS_ENABLED);
+  push_notification_enabled_ = (state == invalidation::INVALIDATIONS_ENABLED);
   if (push_notification_enabled_) {
     DVLOG(1) << "XMPP Notifications enabled";
   } else {
@@ -83,7 +83,7 @@
 }
 
 void DriveNotificationManager::OnIncomingInvalidation(
-    const syncer::TopicInvalidationMap& invalidation_map) {
+    const invalidation::TopicInvalidationMap& invalidation_map) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "XMPP Drive Notification Received";
 
@@ -120,7 +120,8 @@
 }
 
 std::string DriveNotificationManager::GetOwnerName() const { return "Drive"; }
-bool DriveNotificationManager::IsPublicTopic(const syncer::Topic& topic) const {
+bool DriveNotificationManager::IsPublicTopic(
+    const invalidation::Topic& topic) const {
   return base::StartsWith(topic, kTeamDriveChangePrefix);
 }
 
@@ -141,8 +142,8 @@
   observers_.RemoveObserver(observer);
 
   if (!observers_.might_have_observers()) {
-    CHECK(invalidation_service_->UpdateInterestedTopics(this,
-                                                        syncer::TopicSet()));
+    CHECK(invalidation_service_->UpdateInterestedTopics(
+        this, invalidation::TopicSet()));
     polling_timer_.Stop();
     batch_timer_.Stop();
     invalidated_change_ids_.clear();
@@ -265,7 +266,7 @@
   if (!invalidation_service_)
     return;
 
-  syncer::TopicSet topics;
+  invalidation::TopicSet topics;
   topics.insert(GetDriveInvalidationTopic());
 
   for (const auto& team_drive_id : team_drive_ids_) {
@@ -300,11 +301,12 @@
   return "";
 }
 
-syncer::Topic DriveNotificationManager::GetDriveInvalidationTopic() const {
+invalidation::Topic DriveNotificationManager::GetDriveInvalidationTopic()
+    const {
   return kDriveInvalidationTopicName;
 }
 
-syncer::Topic DriveNotificationManager::GetTeamDriveInvalidationTopic(
+invalidation::Topic DriveNotificationManager::GetTeamDriveInvalidationTopic(
     const std::string& team_drive_id) const {
   return base::StrCat({kTeamDriveChangePrefix, team_drive_id});
 }
diff --git a/components/drive/drive_notification_manager.h b/components/drive/drive_notification_manager.h
index 5c4698434..ed28c21 100644
--- a/components/drive/drive_notification_manager.h
+++ b/components/drive/drive_notification_manager.h
@@ -34,7 +34,7 @@
 // 1. XMPP invalidation is received from Google Drive.
 // 2. Polling timer counts down.
 class DriveNotificationManager : public KeyedService,
-                                 public syncer::InvalidationHandler {
+                                 public invalidation::InvalidationHandler {
  public:
   // |clock| can be injected for testing.
   explicit DriveNotificationManager(
@@ -45,12 +45,12 @@
   // KeyedService override.
   void Shutdown() override;
 
-  // syncer::InvalidationHandler implementation.
-  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  // invalidation::InvalidationHandler implementation.
+  void OnInvalidatorStateChange(invalidation::InvalidatorState state) override;
   void OnIncomingInvalidation(
-      const syncer::TopicInvalidationMap& invalidation_map) override;
+      const invalidation::TopicInvalidationMap& invalidation_map) override;
   std::string GetOwnerName() const override;
-  bool IsPublicTopic(const syncer::Topic& topic) const override;
+  bool IsPublicTopic(const invalidation::Topic& topic) const override;
 
   void AddObserver(DriveNotificationObserver* observer);
   void RemoveObserver(DriveNotificationObserver* observer);
@@ -112,8 +112,8 @@
   // Returns a string representation of NotificationSource.
   static std::string NotificationSourceToString(NotificationSource source);
 
-  syncer::Topic GetDriveInvalidationTopic() const;
-  syncer::Topic GetTeamDriveInvalidationTopic(
+  invalidation::Topic GetDriveInvalidationTopic() const;
+  invalidation::Topic GetTeamDriveInvalidationTopic(
       const std::string& team_drive_id) const;
   std::string ExtractTeamDriveId(base::StringPiece topic_name) const;
 
diff --git a/components/drive/drive_notification_manager_unittest.cc b/components/drive/drive_notification_manager_unittest.cc
index cbb4439..0a679671d 100644
--- a/components/drive/drive_notification_manager_unittest.cc
+++ b/components/drive/drive_notification_manager_unittest.cc
@@ -16,7 +16,7 @@
 
 namespace {
 
-const syncer::Topic kDefaultCorpusTopic = "Drive";
+const invalidation::Topic kDefaultCorpusTopic = "Drive";
 
 struct ShutdownHelper {
   template <typename T>
@@ -30,7 +30,7 @@
 
 class FakeDriveNotificationObserver : public DriveNotificationObserver {
  public:
-  ~FakeDriveNotificationObserver() override {}
+  ~FakeDriveNotificationObserver() override = default;
 
   // DriveNotificationObserver overrides
   void OnNotificationReceived(
@@ -50,7 +50,7 @@
   std::map<std::string, int64_t> notification_ids_;
 };
 
-syncer::Topic CreateTeamDriveInvalidationTopic(
+invalidation::Topic CreateTeamDriveInvalidationTopic(
     const std::string& team_drive_id) {
   return base::StrCat({"team-drive-", team_drive_id});
 }
@@ -94,12 +94,12 @@
   auto subscribed_topics = fake_invalidation_service_->invalidator_registrar()
                                .GetAllSubscribedTopics();
 
-  // TODO(crbug.com/1029698): replace syncer::Topics with syncer::TopicSet once
-  // |is_public| become the part of dedicated syncer::Topic struct. This should
-  // simplify this test.
-  syncer::Topics expected_topics;
+  // TODO(crbug.com/1029698): replace invalidation::Topics with
+  // invalidation::TopicSet once |is_public| become the part of dedicated
+  // invalidation::Topic struct. This should simplify this test.
+  invalidation::Topics expected_topics;
   expected_topics.emplace(kDefaultCorpusTopic,
-                          syncer::TopicMetadata{/*is_public=*/false});
+                          invalidation::TopicMetadata{/*is_public=*/false});
   EXPECT_EQ(expected_topics, subscribed_topics);
 
   const std::string team_drive_id_1 = "td_id_1";
@@ -112,7 +112,7 @@
                           .GetAllSubscribedTopics();
 
   expected_topics.emplace(team_drive_1_topic,
-                          syncer::TopicMetadata{/*is_public=*/true});
+                          invalidation::TopicMetadata{/*is_public=*/true});
   EXPECT_EQ(expected_topics, subscribed_topics);
 
   // Remove the team drive.
@@ -134,9 +134,9 @@
                           .GetAllSubscribedTopics();
 
   expected_topics.emplace(team_drive_1_topic,
-                          syncer::TopicMetadata{/*is_public=*/true});
+                          invalidation::TopicMetadata{/*is_public=*/true});
   expected_topics.emplace(team_drive_2_topic,
-                          syncer::TopicMetadata{/*is_public=*/true});
+                          invalidation::TopicMetadata{/*is_public=*/true});
   EXPECT_EQ(expected_topics, subscribed_topics);
 
   // Remove the first team drive.
@@ -162,7 +162,7 @@
   // Emitting an invalidation should not call our observer until the timer
   // expires.
   fake_invalidation_service_->EmitInvalidationForTest(
-      syncer::Invalidation::InitUnknownVersion(kDefaultCorpusTopic));
+      invalidation::Invalidation::InitUnknownVersion(kDefaultCorpusTopic));
   EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());
 
   task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30));
@@ -181,7 +181,7 @@
   // Emit invalidation for default corpus, should not emit a team drive
   // invalidation.
   fake_invalidation_service_->EmitInvalidationForTest(
-      syncer::Invalidation::Init(kDefaultCorpusTopic, 1, ""));
+      invalidation::Invalidation::Init(kDefaultCorpusTopic, 1, ""));
   EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());
 
   task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30));
@@ -193,7 +193,7 @@
 
   // Emit team drive invalidation
   fake_invalidation_service_->EmitInvalidationForTest(
-      syncer::Invalidation::Init(team_drive_1_topic, 2, ""));
+      invalidation::Invalidation::Init(team_drive_1_topic, 2, ""));
   EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());
 
   task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30));
@@ -203,17 +203,17 @@
 
   // Emit both default corpus and team drive.
   fake_invalidation_service_->EmitInvalidationForTest(
-      syncer::Invalidation::Init(kDefaultCorpusTopic, 1, ""));
+      invalidation::Invalidation::Init(kDefaultCorpusTopic, 1, ""));
   fake_invalidation_service_->EmitInvalidationForTest(
-      syncer::Invalidation::Init(team_drive_1_topic, 2, ""));
+      invalidation::Invalidation::Init(team_drive_1_topic, 2, ""));
 
   // Emit with an earlier version. This should be ignored.
   fake_invalidation_service_->EmitInvalidationForTest(
-      syncer::Invalidation::Init(kDefaultCorpusTopic, 0, ""));
+      invalidation::Invalidation::Init(kDefaultCorpusTopic, 0, ""));
 
   // Emit without a version. This should be ignored too.
   fake_invalidation_service_->EmitInvalidationForTest(
-      syncer::Invalidation::InitUnknownVersion(kDefaultCorpusTopic));
+      invalidation::Invalidation::InitUnknownVersion(kDefaultCorpusTopic));
 
   EXPECT_TRUE(drive_notification_observer_->GetNotificationIds().empty());
 
@@ -228,11 +228,12 @@
   auto subscribed_topics = fake_invalidation_service_->invalidator_registrar()
                                .GetAllSubscribedTopics();
 
-  // TODO(crbug.com/1029698): replace syncer::Topics with syncer::TopicSet once
-  // |is_public| become the part of dedicated syncer::Topic struct.
-  syncer::Topics expected_topics;
+  // TODO(crbug.com/1029698): replace invalidation::Topics with
+  // invalidation::TopicSet once |is_public| become the part of dedicated
+  // invalidation::Topic struct.
+  invalidation::Topics expected_topics;
   expected_topics.emplace(kDefaultCorpusTopic,
-                          syncer::TopicMetadata{/*is_public=*/false});
+                          invalidation::TopicMetadata{/*is_public=*/false});
   EXPECT_EQ(expected_topics, subscribed_topics);
 
   // Stop observing drive notification manager.
@@ -241,7 +242,7 @@
 
   subscribed_topics = fake_invalidation_service_->invalidator_registrar()
                           .GetAllSubscribedTopics();
-  EXPECT_EQ(syncer::Topics(), subscribed_topics);
+  EXPECT_EQ(invalidation::Topics(), subscribed_topics);
 
   // Start observing drive notification manager again. It should subscribe to
   // the previously subscried topics.
diff --git a/components/enterprise/browser/controller/browser_dm_token_storage.cc b/components/enterprise/browser/controller/browser_dm_token_storage.cc
index 4cfb0ee..aed5133 100644
--- a/components/enterprise/browser/controller/browser_dm_token_storage.cc
+++ b/components/enterprise/browser/controller/browser_dm_token_storage.cc
@@ -15,10 +15,8 @@
 #include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
-#include "base/run_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/system/sys_info.h"
 #include "base/task/post_task.h"
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_task_runner_handle.h"
@@ -31,13 +29,6 @@
 
 constexpr char kInvalidTokenValue[] = "INVALID_DM_TOKEN";
 
-void OnHardwarePlatformInfo(base::OnceClosure quit_closure,
-                            std::string* out,
-                            base::SysInfo::HardwareInfo info) {
-  *out = info.serial_number;
-  std::move(quit_closure).Run();
-}
-
 DMToken CreateValidToken(const std::string& dm_token) {
   DCHECK_NE(dm_token, kInvalidTokenValue);
   DCHECK(!dm_token.empty());
@@ -96,17 +87,6 @@
   return client_id_;
 }
 
-std::string BrowserDMTokenStorage::RetrieveSerialNumber() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (!serial_number_) {
-    serial_number_ = InitSerialNumber();
-    DVLOG(1) << "Serial number= " << serial_number_.value();
-  }
-
-  return serial_number_.value();
-}
-
 std::string BrowserDMTokenStorage::RetrieveEnrollmentToken() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -209,20 +189,4 @@
                                    std::move(reply));
 }
 
-std::string BrowserDMTokenStorage::InitSerialNumber() {
-  // GetHardwareInfo is asynchronous, but we need this synchronously. This call
-  // will only happens once, as we cache the value. This will eventually be
-  // moved earlier in Chrome's startup as it will be needed by the registration
-  // as well.
-  // TODO(crbug.com/907518): Move this earlier and make it async.
-  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-  std::string serial_number;
-  base::SysInfo::GetHardwareInfo(base::BindOnce(
-      &OnHardwarePlatformInfo, run_loop.QuitClosure(), &serial_number));
-
-  run_loop.Run();
-
-  return serial_number;
-}
-
 }  // namespace policy
diff --git a/components/enterprise/browser/controller/browser_dm_token_storage.h b/components/enterprise/browser/controller/browser_dm_token_storage.h
index 619046d3..4491cd0 100644
--- a/components/enterprise/browser/controller/browser_dm_token_storage.h
+++ b/components/enterprise/browser/controller/browser_dm_token_storage.h
@@ -69,8 +69,6 @@
 
   // Returns a client ID unique to the machine.
   std::string RetrieveClientId();
-  // Returns the serial number of the machine.
-  std::string RetrieveSerialNumber();
   // Returns the enrollment token, or an empty string if there is none.
   std::string RetrieveEnrollmentToken();
   // Asynchronously stores |dm_token| and calls |callback| with a boolean to
@@ -120,10 +118,6 @@
   // is called the first time the BrowserDMTokenStorage is interacted with.
   void InitIfNeeded();
 
-  // Gets the client ID and returns it. This implementation is shared by all
-  // platforms.
-  std::string InitSerialNumber();
-
   // Saves the DM token.
   void SaveDMToken(const std::string& token);
 
@@ -133,7 +127,6 @@
   bool is_initialized_;
 
   std::string client_id_;
-  base::Optional<std::string> serial_number_;
   std::string enrollment_token_;
   DMToken dm_token_;
   bool should_display_error_message_on_failure_;
diff --git a/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc b/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc
index ed5f4257..32abb4d 100644
--- a/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc
+++ b/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/macros.h"
-#include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h"
diff --git a/components/history/content/browser/web_contents_top_sites_observer.cc b/components/history/content/browser/web_contents_top_sites_observer.cc
index 526a642..77ddd91 100644
--- a/components/history/content/browser/web_contents_top_sites_observer.cc
+++ b/components/history/content/browser/web_contents_top_sites_observer.cc
@@ -29,9 +29,10 @@
   // Type-wise, we only care about navigating to a new page, or renavigating to
   // an existing navigation entry.
   if (top_sites_ && load_details.is_main_frame &&
-      (load_details.type == content::NavigationType::NAVIGATION_TYPE_NEW_PAGE ||
+      (load_details.type ==
+           content::NavigationType::NAVIGATION_TYPE_NEW_ENTRY ||
        load_details.type ==
-           content::NavigationType::NAVIGATION_TYPE_EXISTING_PAGE)) {
+           content::NavigationType::NAVIGATION_TYPE_EXISTING_ENTRY)) {
     // Only report the Virtual URL. The virtual URL, when it differs from the
     // actual URL that is loaded in the renderer, is the one meant to be shown
     // to the user in all UI.
diff --git a/components/invalidation/impl/channels_states.cc b/components/invalidation/impl/channels_states.cc
index 8ead1b1..15685d4 100644
--- a/components/invalidation/impl/channels_states.cc
+++ b/components/invalidation/impl/channels_states.cc
@@ -4,7 +4,7 @@
 
 #include "components/invalidation/impl/channels_states.h"
 
-namespace syncer {
+namespace invalidation {
 
 const char* FcmChannelStateToString(FcmChannelState state) {
   switch (state) {
@@ -30,4 +30,4 @@
   }
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/channels_states.h b/components/invalidation/impl/channels_states.h
index 97d84b7e..abb6d30 100644
--- a/components/invalidation/impl/channels_states.h
+++ b/components/invalidation/impl/channels_states.h
@@ -5,7 +5,7 @@
 #ifndef COMPONENTS_INVALIDATION_IMPL_CHANNELS_STATES_H_
 #define COMPONENTS_INVALIDATION_IMPL_CHANNELS_STATES_H_
 
-namespace syncer {
+namespace invalidation {
 
 enum class FcmChannelState {
   NOT_STARTED,
@@ -30,6 +30,6 @@
 
 const char* SubscriptionChannelStateToString(SubscriptionChannelState state);
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_CHANNELS_STATES_H_
diff --git a/components/invalidation/impl/fake_invalidation_handler.cc b/components/invalidation/impl/fake_invalidation_handler.cc
index 8ba70d1..1181b361 100644
--- a/components/invalidation/impl/fake_invalidation_handler.cc
+++ b/components/invalidation/impl/fake_invalidation_handler.cc
@@ -4,7 +4,7 @@
 
 #include "components/invalidation/impl/fake_invalidation_handler.h"
 
-namespace syncer {
+namespace invalidation {
 
 FakeInvalidationHandler::FakeInvalidationHandler()
     : state_(DEFAULT_INVALIDATION_ERROR),
@@ -45,8 +45,8 @@
   return owner_name_;
 }
 
-bool FakeInvalidationHandler::IsPublicTopic(const syncer::Topic& topic) const {
+bool FakeInvalidationHandler::IsPublicTopic(const Topic& topic) const {
   return topic == "PREFERENCE";
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/fake_invalidation_handler.h b/components/invalidation/impl/fake_invalidation_handler.h
index 32a84c48..cf4ed98 100644
--- a/components/invalidation/impl/fake_invalidation_handler.h
+++ b/components/invalidation/impl/fake_invalidation_handler.h
@@ -10,7 +10,7 @@
 #include "components/invalidation/public/invalidation_handler.h"
 #include "components/invalidation/public/topic_invalidation_map.h"
 
-namespace syncer {
+namespace invalidation {
 
 class FakeInvalidationHandler : public InvalidationHandler {
  public:
@@ -30,7 +30,7 @@
   void OnIncomingInvalidation(
       const TopicInvalidationMap& invalidation_map) override;
   std::string GetOwnerName() const override;
-  bool IsPublicTopic(const syncer::Topic& topic) const override;
+  bool IsPublicTopic(const Topic& topic) const override;
 
  private:
   InvalidatorState state_;
@@ -39,6 +39,6 @@
   std::string owner_name_;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_FAKE_INVALIDATION_HANDLER_H_
diff --git a/components/invalidation/impl/fake_invalidation_service.cc b/components/invalidation/impl/fake_invalidation_service.cc
index ae4febb0..65c60aca 100644
--- a/components/invalidation/impl/fake_invalidation_service.cc
+++ b/components/invalidation/impl/fake_invalidation_service.cc
@@ -14,25 +14,24 @@
 
 FakeInvalidationService::FakeInvalidationService()
     : client_id_(GenerateInvalidatorClientId()) {
-  syncer::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(
+  InvalidatorRegistrarWithMemory::RegisterProfilePrefs(
       pref_service_.registry());
-  invalidator_registrar_ =
-      std::make_unique<syncer::InvalidatorRegistrarWithMemory>(
-          &pref_service_, /*sender_id=*/"sender_id",
-          /*migrate_old_prefs=*/false);
-  invalidator_registrar_->UpdateInvalidatorState(syncer::INVALIDATIONS_ENABLED);
+  invalidator_registrar_ = std::make_unique<InvalidatorRegistrarWithMemory>(
+      &pref_service_, /*sender_id=*/"sender_id",
+      /*migrate_old_prefs=*/false);
+  invalidator_registrar_->UpdateInvalidatorState(INVALIDATIONS_ENABLED);
 }
 
 FakeInvalidationService::~FakeInvalidationService() = default;
 
 void FakeInvalidationService::RegisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) {
+    InvalidationHandler* handler) {
   invalidator_registrar_->RegisterHandler(handler);
 }
 
 bool FakeInvalidationService::UpdateInterestedTopics(
-    syncer::InvalidationHandler* handler,
-    const syncer::TopicSet& legacy_topic_set) {
+    InvalidationHandler* handler,
+    const TopicSet& legacy_topic_set) {
   std::set<TopicData> topic_set;
   for (const auto& topic_name : legacy_topic_set) {
     topic_set.insert(TopicData(topic_name, handler->IsPublicTopic(topic_name)));
@@ -41,11 +40,11 @@
 }
 
 void FakeInvalidationService::UnregisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) {
+    InvalidationHandler* handler) {
   invalidator_registrar_->UnregisterHandler(handler);
 }
 
-syncer::InvalidatorState FakeInvalidationService::GetInvalidatorState() const {
+InvalidatorState FakeInvalidationService::GetInvalidatorState() const {
   return invalidator_registrar_->GetInvalidatorState();
 }
 
@@ -63,20 +62,18 @@
   caller.Run(value);
 }
 
-void FakeInvalidationService::SetInvalidatorState(
-    syncer::InvalidatorState state) {
+void FakeInvalidationService::SetInvalidatorState(InvalidatorState state) {
   invalidator_registrar_->UpdateInvalidatorState(state);
 }
 
 void FakeInvalidationService::EmitInvalidationForTest(
-    const syncer::Invalidation& invalidation) {
+    const Invalidation& invalidation) {
   // This function might need to modify the |invalidation|, so we start by
   // making an identical copy of it.
-  syncer::Invalidation invalidation_copy(invalidation);
+  Invalidation invalidation_copy(invalidation);
 
   // If no one is listening to this invalidation, do not send it out.
-  syncer::Topics subscribed_topics =
-      invalidator_registrar_->GetAllSubscribedTopics();
+  Topics subscribed_topics = invalidator_registrar_->GetAllSubscribedTopics();
   if (subscribed_topics.find(invalidation.topic()) == subscribed_topics.end()) {
     mock_ack_handler_.RegisterUnsentInvalidation(&invalidation_copy);
     return;
@@ -85,12 +82,12 @@
   // Otherwise, register the invalidation with the mock_ack_handler_ and deliver
   // it to the appropriate consumer.
   mock_ack_handler_.RegisterInvalidation(&invalidation_copy);
-  syncer::TopicInvalidationMap invalidation_map;
+  TopicInvalidationMap invalidation_map;
   invalidation_map.Insert(invalidation_copy);
   invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map);
 }
 
-syncer::MockAckHandler* FakeInvalidationService::GetMockAckHandler() {
+MockAckHandler* FakeInvalidationService::GetMockAckHandler() {
   return &mock_ack_handler_;
 }
 
diff --git a/components/invalidation/impl/fake_invalidation_service.h b/components/invalidation/impl/fake_invalidation_service.h
index c1805560..2733d3b1 100644
--- a/components/invalidation/impl/fake_invalidation_service.h
+++ b/components/invalidation/impl/fake_invalidation_service.h
@@ -15,12 +15,9 @@
 #include "components/invalidation/public/invalidation_service.h"
 #include "components/prefs/testing_pref_service.h"
 
-namespace syncer {
-class Invalidation;
-}
-
 namespace invalidation {
 
+class Invalidation;
 class InvalidationLogger;
 
 // An InvalidationService that emits invalidations only when
@@ -33,39 +30,36 @@
       delete;
   ~FakeInvalidationService() override;
 
-  void RegisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) override;
-  bool UpdateInterestedTopics(syncer::InvalidationHandler* handler,
-                              const syncer::TopicSet& topics) override;
-  void UnregisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) override;
+  void RegisterInvalidationHandler(InvalidationHandler* handler) override;
+  bool UpdateInterestedTopics(InvalidationHandler* handler,
+                              const TopicSet& topics) override;
+  void UnregisterInvalidationHandler(InvalidationHandler* handler) override;
 
-  syncer::InvalidatorState GetInvalidatorState() const override;
+  InvalidatorState GetInvalidatorState() const override;
   std::string GetInvalidatorClientId() const override;
   InvalidationLogger* GetInvalidationLogger() override;
   void RequestDetailedStatus(
       base::RepeatingCallback<void(const base::DictionaryValue&)> caller)
       const override;
 
-  void SetInvalidatorState(syncer::InvalidatorState state);
+  void SetInvalidatorState(InvalidatorState state);
 
-  const syncer::InvalidatorRegistrarWithMemory& invalidator_registrar() const {
+  const InvalidatorRegistrarWithMemory& invalidator_registrar() const {
     return *invalidator_registrar_;
   }
 
-  void EmitInvalidationForTest(const syncer::Invalidation& invalidation);
+  void EmitInvalidationForTest(const Invalidation& invalidation);
 
   // Emitted invalidations will be hooked up to this AckHandler.  Clients can
   // query it to assert the invalidaitons are being acked properly.
-  syncer::MockAckHandler* GetMockAckHandler();
+  MockAckHandler* GetMockAckHandler();
 
  private:
   std::string client_id_;
   // |pref_service_| must outlive |invalidator_registrar_|.
   TestingPrefServiceSimple pref_service_;
-  std::unique_ptr<syncer::InvalidatorRegistrarWithMemory>
-      invalidator_registrar_;
-  syncer::MockAckHandler mock_ack_handler_;
+  std::unique_ptr<InvalidatorRegistrarWithMemory> invalidator_registrar_;
+  MockAckHandler mock_ack_handler_;
 };
 
 }  // namespace invalidation
diff --git a/components/invalidation/impl/fcm_invalidation_listener.cc b/components/invalidation/impl/fcm_invalidation_listener.cc
index f875ec9..fb223b6 100644
--- a/components/invalidation/impl/fcm_invalidation_listener.cc
+++ b/components/invalidation/impl/fcm_invalidation_listener.cc
@@ -11,7 +11,7 @@
 #include "components/invalidation/public/topic_invalidation_map.h"
 #include "components/prefs/pref_service.h"
 
-namespace syncer {
+namespace invalidation {
 
 FCMInvalidationListener::FCMInvalidationListener(
     std::unique_ptr<FCMSyncNetworkChannel> network_channel)
@@ -128,7 +128,7 @@
 }
 
 void FCMInvalidationListener::Acknowledge(const Topic& topic,
-                                          const syncer::AckHandle& handle) {
+                                          const AckHandle& handle) {
   auto lookup = unacked_invalidations_map_.find(topic);
   if (lookup == unacked_invalidations_map_.end()) {
     DLOG(WARNING) << "Received acknowledgement for untracked topic";
@@ -138,7 +138,7 @@
 }
 
 void FCMInvalidationListener::Drop(const Topic& topic,
-                                   const syncer::AckHandle& handle) {
+                                   const AckHandle& handle) {
   auto lookup = unacked_invalidations_map_.find(topic);
   if (lookup == unacked_invalidations_map_.end()) {
     DLOG(WARNING) << "Received drop for untracked topic";
@@ -257,4 +257,4 @@
   return status;
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/fcm_invalidation_listener.h b/components/invalidation/impl/fcm_invalidation_listener.h
index f8b787b..f06b99ec 100644
--- a/components/invalidation/impl/fcm_invalidation_listener.h
+++ b/components/invalidation/impl/fcm_invalidation_listener.h
@@ -18,7 +18,7 @@
 #include "components/invalidation/public/invalidator_state.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
-namespace syncer {
+namespace invalidation {
 
 class TopicInvalidationMap;
 
@@ -66,9 +66,8 @@
   void ClearInstanceIDToken();
 
   // AckHandler implementation.
-  void Acknowledge(const Topic& topic,
-                   const syncer::AckHandle& handle) override;
-  void Drop(const Topic& topic, const syncer::AckHandle& handle) override;
+  void Acknowledge(const Topic& topic, const AckHandle& handle) override;
+  void Drop(const Topic& topic, const AckHandle& handle) override;
 
   // FCMSyncNetworkChannel::Observer implementation.
   void OnFCMChannelStateChanged(FcmChannelState state) override;
@@ -151,6 +150,6 @@
   base::WeakPtrFactory<FCMInvalidationListener> weak_factory_{this};
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_FCM_INVALIDATION_LISTENER_H_
diff --git a/components/invalidation/impl/fcm_invalidation_listener_unittest.cc b/components/invalidation/impl/fcm_invalidation_listener_unittest.cc
index 84c1d28..bcea44d 100644
--- a/components/invalidation/impl/fcm_invalidation_listener_unittest.cc
+++ b/components/invalidation/impl/fcm_invalidation_listener_unittest.cc
@@ -20,7 +20,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -431,4 +431,4 @@
 
 }  // namespace
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/fcm_invalidation_service.cc b/components/invalidation/impl/fcm_invalidation_service.cc
index e03883b..51963792 100644
--- a/components/invalidation/impl/fcm_invalidation_service.cc
+++ b/components/invalidation/impl/fcm_invalidation_service.cc
@@ -114,8 +114,7 @@
   // and token is available). As currently observed, FCMInvalidationService
   // isn't always notified on Android when token is available.
   if (base::FeatureList::IsEnabled(
-          invalidation::switches::
-              kFCMInvalidationsStartOnceActiveAccountAvailable)) {
+          switches::kFCMInvalidationsStartOnceActiveAccountAvailable)) {
     valid_account_info_available =
         !identity_provider_->GetActiveAccountId().empty();
   }
diff --git a/components/invalidation/impl/fcm_invalidation_service_base.cc b/components/invalidation/impl/fcm_invalidation_service_base.cc
index 955fbcb..381126c 100644
--- a/components/invalidation/impl/fcm_invalidation_service_base.cc
+++ b/components/invalidation/impl/fcm_invalidation_service_base.cc
@@ -57,8 +57,7 @@
 
 FCMInvalidationServiceBase::~FCMInvalidationServiceBase() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  invalidator_registrar_.UpdateInvalidatorState(
-      syncer::INVALIDATOR_SHUTTING_DOWN);
+  invalidator_registrar_.UpdateInvalidatorState(INVALIDATOR_SHUTTING_DOWN);
 
   if (IsStarted()) {
     StopInvalidator();
@@ -67,15 +66,13 @@
 
 // static
 void FCMInvalidationServiceBase::RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterStringPref(
-      invalidation::prefs::kFCMInvalidationClientIDCacheDeprecated,
-      /*default_value=*/std::string());
-  registry->RegisterDictionaryPref(
-      invalidation::prefs::kInvalidationClientIDCache);
+  registry->RegisterStringPref(prefs::kFCMInvalidationClientIDCacheDeprecated,
+                               /*default_value=*/std::string());
+  registry->RegisterDictionaryPref(prefs::kInvalidationClientIDCache);
 }
 
 void FCMInvalidationServiceBase::RegisterInvalidationHandler(
-    syncer::InvalidationHandler* handler) {
+    InvalidationHandler* handler) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "Registering an invalidation handler";
   invalidator_registrar_.RegisterHandler(handler);
@@ -85,8 +82,8 @@
 }
 
 bool FCMInvalidationServiceBase::UpdateInterestedTopics(
-    syncer::InvalidationHandler* handler,
-    const syncer::TopicSet& legacy_topic_set) {
+    InvalidationHandler* handler,
+    const TopicSet& legacy_topic_set) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   update_was_requested_ = true;
   DVLOG(2) << "Subscribing to topics: " << legacy_topic_set.size();
@@ -106,15 +103,14 @@
 }
 
 void FCMInvalidationServiceBase::UnregisterInvalidationHandler(
-    syncer::InvalidationHandler* handler) {
+    InvalidationHandler* handler) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "Unregistering";
   invalidator_registrar_.UnregisterHandler(handler);
   logger_.OnUnregistration(handler->GetOwnerName());
 }
 
-syncer::InvalidatorState FCMInvalidationServiceBase::GetInvalidatorState()
-    const {
+InvalidatorState FCMInvalidationServiceBase::GetInvalidatorState() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (invalidation_listener_) {
     DVLOG(2) << "GetInvalidatorState returning "
@@ -122,7 +118,7 @@
     return invalidator_registrar_.GetInvalidatorState();
   }
   DVLOG(2) << "Invalidator currently stopped";
-  return syncer::STOPPED;
+  return STOPPED;
 }
 
 std::string FCMInvalidationServiceBase::GetInvalidatorClientId() const {
@@ -145,20 +141,20 @@
 }
 
 void FCMInvalidationServiceBase::OnInvalidate(
-    const syncer::TopicInvalidationMap& invalidation_map) {
+    const TopicInvalidationMap& invalidation_map) {
   invalidator_registrar_.DispatchInvalidationsToHandlers(invalidation_map);
 
   logger_.OnInvalidation(invalidation_map);
 }
 
 void FCMInvalidationServiceBase::OnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
+    InvalidatorState state) {
   invalidator_registrar_.UpdateInvalidatorState(state);
   logger_.OnStateChange(state);
 }
 
 void FCMInvalidationServiceBase::InitForTest(
-    std::unique_ptr<syncer::FCMInvalidationListener> invalidation_listener) {
+    std::unique_ptr<FCMInvalidationListener> invalidation_listener) {
   // Here we perform the equivalent of Init() and StartInvalidator(), but with
   // some minor changes to account for the fact that we're injecting the
   // invalidation_listener.
@@ -211,7 +207,7 @@
   // handler for the incoming messages, which is crucial on Android, because on
   // the startup cached messages might exists.
   invalidation_listener_ =
-      std::make_unique<syncer::FCMInvalidationListener>(std::move(network));
+      std::make_unique<FCMInvalidationListener>(std::move(network));
   auto subscription_manager = per_user_topic_subscription_manager_callback_.Run(
       sender_id_, /*migrate_prefs=*/sender_id_ == kInvalidationGCMSenderId);
   invalidation_listener_->Start(this, std::move(subscription_manager));
diff --git a/components/invalidation/impl/fcm_invalidation_service_base.h b/components/invalidation/impl/fcm_invalidation_service_base.h
index 56f99c5e..69249cc 100644
--- a/components/invalidation/impl/fcm_invalidation_service_base.h
+++ b/components/invalidation/impl/fcm_invalidation_service_base.h
@@ -21,31 +21,28 @@
 class InstanceIDDriver;
 }
 
-namespace syncer {
-class FCMNetworkHandler;
-class PerUserTopicSubscriptionManager;
-}  // namespace syncer
-
 namespace invalidation {
 
+class FCMNetworkHandler;
+class PerUserTopicSubscriptionManager;
+
 using FCMNetworkHandlerCallback =
-    base::RepeatingCallback<std::unique_ptr<syncer::FCMNetworkHandler>(
+    base::RepeatingCallback<std::unique_ptr<FCMNetworkHandler>(
         const std::string& sender_id,
         const std::string& app_id)>;
 
 using PerUserTopicSubscriptionManagerCallback =
-    base::RepeatingCallback<std::unique_ptr<
-        syncer::PerUserTopicSubscriptionManager>(const std::string& project_id,
-                                                 bool migrate_prefs)>;
+    base::RepeatingCallback<std::unique_ptr<PerUserTopicSubscriptionManager>(
+        const std::string& project_id,
+        bool migrate_prefs)>;
 
 // This InvalidationService wraps the C++ Invalidation Client (FCM) library.
 // It provides invalidations for desktop platforms (Win, Mac, Linux).
 // Subclasses should implement Init to set up their initial state and call
 // StartInvalidator/StopInvalidator when they want to start/stop receiving
 // invalidations.
-class FCMInvalidationServiceBase
-    : public InvalidationService,
-      public syncer::FCMInvalidationListener::Delegate {
+class FCMInvalidationServiceBase : public InvalidationService,
+                                   public FCMInvalidationListener::Delegate {
  public:
   FCMInvalidationServiceBase(
       FCMNetworkHandlerCallback fcm_network_handler_callback,
@@ -65,28 +62,25 @@
 
   // InvalidationService implementation.
   // It is an error to have registered handlers when the service is destroyed.
-  void RegisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) override;
-  bool UpdateInterestedTopics(syncer::InvalidationHandler* handler,
-                              const syncer::TopicSet& topics) override;
-  void UnregisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) override;
-  syncer::InvalidatorState GetInvalidatorState() const override;
+  void RegisterInvalidationHandler(InvalidationHandler* handler) override;
+  bool UpdateInterestedTopics(InvalidationHandler* handler,
+                              const TopicSet& topics) override;
+  void UnregisterInvalidationHandler(InvalidationHandler* handler) override;
+  InvalidatorState GetInvalidatorState() const override;
   std::string GetInvalidatorClientId() const override;
   InvalidationLogger* GetInvalidationLogger() override;
   void RequestDetailedStatus(
       base::RepeatingCallback<void(const base::DictionaryValue&)> caller)
       const override;
 
-  // syncer::FCMInvalidationListener::Delegate implementation.
-  void OnInvalidate(
-      const syncer::TopicInvalidationMap& invalidation_map) override;
-  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  // FCMInvalidationListener::Delegate implementation.
+  void OnInvalidate(const TopicInvalidationMap& invalidation_map) override;
+  void OnInvalidatorStateChange(InvalidatorState state) override;
 
  protected:
   // Initializes with an injected listener.
   void InitForTest(
-      std::unique_ptr<syncer::FCMInvalidationListener> invalidation_listener);
+      std::unique_ptr<FCMInvalidationListener> invalidation_listener);
 
   virtual base::DictionaryValue CollectDebugData() const;
 
@@ -123,7 +117,7 @@
   const std::string GetApplicationName();
 
   const std::string sender_id_;
-  syncer::InvalidatorRegistrarWithMemory invalidator_registrar_;
+  InvalidatorRegistrarWithMemory invalidator_registrar_;
 
   // The invalidation logger object we use to record state changes
   // and invalidations.
@@ -143,7 +137,7 @@
   Diagnostics diagnostic_info_;
 
   // The invalidation listener.
-  std::unique_ptr<syncer::FCMInvalidationListener> invalidation_listener_;
+  std::unique_ptr<FCMInvalidationListener> invalidation_listener_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 };
diff --git a/components/invalidation/impl/fcm_invalidation_service_unittest.cc b/components/invalidation/impl/fcm_invalidation_service_unittest.cc
index c6b71f0..79fc695 100644
--- a/components/invalidation/impl/fcm_invalidation_service_unittest.cc
+++ b/components/invalidation/impl/fcm_invalidation_service_unittest.cc
@@ -43,7 +43,7 @@
 
 namespace {
 
-class TestFCMSyncNetworkChannel : public syncer::FCMSyncNetworkChannel {
+class TestFCMSyncNetworkChannel : public FCMSyncNetworkChannel {
  public:
   void StartListening() override {}
   void StopListening() override {}
@@ -58,11 +58,11 @@
 // FakeFCMInvalidationListener classes that will inherit from
 // FCMInvalidationListener. The reason for such a change is that
 // FCMInvalidationService relies of FCMInvalidationListener class.
-class FakeFCMInvalidationListener : public syncer::FCMInvalidationListener {
+class FakeFCMInvalidationListener : public FCMInvalidationListener {
  public:
   explicit FakeFCMInvalidationListener(
-      std::unique_ptr<syncer::FCMSyncNetworkChannel> network_channel)
-      : syncer::FCMInvalidationListener(std::move(network_channel)) {}
+      std::unique_ptr<FCMSyncNetworkChannel> network_channel)
+      : FCMInvalidationListener(std::move(network_channel)) {}
   ~FakeFCMInvalidationListener() override = default;
 
   void RequestDetailedStatus(
@@ -120,7 +120,7 @@
         /*default_value=*/std::string());
     pref_service_.registry()->RegisterDictionaryPref(
         prefs::kInvalidationClientIDCache);
-    syncer::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(
+    InvalidatorRegistrarWithMemory::RegisterProfilePrefs(
         pref_service_.registry());
   }
 
@@ -150,9 +150,9 @@
 
     invalidation_service_ = std::make_unique<FCMInvalidationService>(
         identity_provider_.get(),
-        base::BindRepeating(&syncer::FCMNetworkHandler::Create,
-                            gcm_driver_.get(), mock_instance_id_driver_.get()),
-        base::BindRepeating(&syncer::PerUserTopicSubscriptionManager::Create,
+        base::BindRepeating(&FCMNetworkHandler::Create, gcm_driver_.get(),
+                            mock_instance_id_driver_.get()),
+        base::BindRepeating(&PerUserTopicSubscriptionManager::Create,
                             identity_provider_.get(), &pref_service_,
                             &url_loader_factory_),
         mock_instance_id_driver_.get(), &pref_service_);
@@ -170,12 +170,12 @@
 
   void DestroyInvalidationService() { invalidation_service_.reset(); }
 
-  void TriggerOnInvalidatorStateChange(syncer::InvalidatorState state) {
+  void TriggerOnInvalidatorStateChange(InvalidatorState state) {
     fake_listener_->EmitStateChangeForTest(state);
   }
 
   void TriggerOnIncomingInvalidation(
-      const syncer::TopicInvalidationMap& invalidation_map) {
+      const TopicInvalidationMap& invalidation_map) {
     fake_listener_->EmitSavedInvalidationsForTest(invalidation_map);
   }
 
@@ -185,8 +185,8 @@
   std::unique_ptr<MockInstanceIDDriver> mock_instance_id_driver_;
   std::unique_ptr<MockInstanceID> mock_instance_id_;
   signin::IdentityTestEnvironment identity_test_env_;
-  std::unique_ptr<invalidation::IdentityProvider> identity_provider_;
-  syncer::FCMInvalidationListener* fake_listener_;  // Owned by the service.
+  std::unique_ptr<IdentityProvider> identity_provider_;
+  FCMInvalidationListener* fake_listener_;  // Owned by the service.
   network::TestURLLoaderFactory url_loader_factory_;
   TestingPrefServiceSimple pref_service_;
 
@@ -242,8 +242,7 @@
       new FCMInvalidationServiceTestDelegate());
 
   delegate->CreateUninitializedInvalidationService();
-  invalidation::InvalidationService* const invalidator =
-      delegate->GetInvalidationService();
+  InvalidationService* const invalidator = delegate->GetInvalidationService();
 
   internal::FakeCallbackContainer fake_container;
   invalidator->RequestDetailedStatus(
diff --git a/components/invalidation/impl/fcm_network_handler.cc b/components/invalidation/impl/fcm_network_handler.cc
index 75b0f30a..a315159 100644
--- a/components/invalidation/impl/fcm_network_handler.cc
+++ b/components/invalidation/impl/fcm_network_handler.cc
@@ -29,7 +29,7 @@
 
 using instance_id::InstanceID;
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -50,25 +50,23 @@
   // This magic value is identical to kInvalidationGCMSenderId, i.e. the value
   // that Sync uses for its invalidations.
   if (sender_id == "8181035976") {
-    if (!base::FeatureList::IsEnabled(
-            invalidation::switches::kSyncInstanceIDTokenTTL)) {
+    if (!base::FeatureList::IsEnabled(switches::kSyncInstanceIDTokenTTL)) {
       return base::TimeDelta();
     }
 
     return base::TimeDelta::FromSeconds(
-        invalidation::switches::kSyncInstanceIDTokenTTLSeconds.Get());
+        switches::kSyncInstanceIDTokenTTLSeconds.Get());
   }
 
   // This magic value is identical to kPolicyFCMInvalidationSenderID, i.e. the
   // value that ChromeOS policy uses for its invalidations.
   if (sender_id == "1013309121859") {
-    if (!base::FeatureList::IsEnabled(
-            invalidation::switches::kPolicyInstanceIDTokenTTL)) {
+    if (!base::FeatureList::IsEnabled(switches::kPolicyInstanceIDTokenTTL)) {
       return base::TimeDelta();
     }
 
     return base::TimeDelta::FromSeconds(
-        invalidation::switches::kPolicyInstanceIDTokenTTLSeconds.Get());
+        switches::kPolicyInstanceIDTokenTTLSeconds.Get());
   }
 
   // The default for all other FCM clients is no TTL.
@@ -172,13 +170,13 @@
 }
 
 // static
-std::unique_ptr<syncer::FCMNetworkHandler> FCMNetworkHandler::Create(
+std::unique_ptr<FCMNetworkHandler> FCMNetworkHandler::Create(
     gcm::GCMDriver* gcm_driver,
     instance_id::InstanceIDDriver* instance_id_driver,
     const std::string& sender_id,
     const std::string& app_id) {
-  return std::make_unique<syncer::FCMNetworkHandler>(
-      gcm_driver, instance_id_driver, sender_id, app_id);
+  return std::make_unique<FCMNetworkHandler>(gcm_driver, instance_id_driver,
+                                             sender_id, app_id);
 }
 
 void FCMNetworkHandler::StartListening() {
@@ -390,4 +388,4 @@
   }
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/fcm_network_handler.h b/components/invalidation/impl/fcm_network_handler.h
index b5cd8864..df9ab9a4 100644
--- a/components/invalidation/impl/fcm_network_handler.h
+++ b/components/invalidation/impl/fcm_network_handler.h
@@ -23,7 +23,7 @@
 class InstanceIDDriver;
 }
 
-namespace syncer {
+namespace invalidation {
 
 /*
  * The class responsible for communication via GCM channel:
@@ -45,7 +45,7 @@
   ~FCMNetworkHandler() override;
 
   // Just calls std::make_unique. For ease of base::Bind'ing.
-  static std::unique_ptr<syncer::FCMNetworkHandler> Create(
+  static std::unique_ptr<FCMNetworkHandler> Create(
       gcm::GCMDriver* gcm_driver,
       instance_id::InstanceIDDriver* instance_id_driver,
       const std::string& sender_id,
@@ -123,6 +123,6 @@
   base::WeakPtrFactory<FCMNetworkHandler> weak_ptr_factory_{this};
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_FCM_NETWORK_HANDLER_H_
diff --git a/components/invalidation/impl/fcm_network_handler_unittests.cc b/components/invalidation/impl/fcm_network_handler_unittests.cc
index 40889ae..d636025 100644
--- a/components/invalidation/impl/fcm_network_handler_unittests.cc
+++ b/components/invalidation/impl/fcm_network_handler_unittests.cc
@@ -37,7 +37,7 @@
 using testing::StrictMock;
 using testing::WithArg;
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -247,8 +247,8 @@
         {"time_to_live_seconds", base::NumberToString(kTimeToLiveInSeconds)}};
     override_features_.InitWithFeaturesAndParameters(
         /*enabled_features=*/
-        {{invalidation::switches::kSyncInstanceIDTokenTTL, feature_params},
-         {invalidation::switches::kPolicyInstanceIDTokenTTL, feature_params}},
+        {{switches::kSyncInstanceIDTokenTTL, feature_params},
+         {switches::kPolicyInstanceIDTokenTTL, feature_params}},
         /*disabled_features=*/{});
   }
 
@@ -508,4 +508,4 @@
   MakeHandler(/*sender_id=*/"fake_sender_id")->StartListening();
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/fcm_sync_network_channel.cc b/components/invalidation/impl/fcm_sync_network_channel.cc
index c80ca80..37bf229 100644
--- a/components/invalidation/impl/fcm_sync_network_channel.cc
+++ b/components/invalidation/impl/fcm_sync_network_channel.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 
-namespace syncer {
+namespace invalidation {
 
 FCMSyncNetworkChannel::FCMSyncNetworkChannel() : received_messages_count_(0) {}
 
@@ -60,4 +60,4 @@
   return true;
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/fcm_sync_network_channel.h b/components/invalidation/impl/fcm_sync_network_channel.h
index 0a6c0b3..2ecd9b9d 100644
--- a/components/invalidation/impl/fcm_sync_network_channel.h
+++ b/components/invalidation/impl/fcm_sync_network_channel.h
@@ -12,7 +12,7 @@
 #include "base/values.h"
 #include "components/invalidation/impl/channels_states.h"
 
-namespace syncer {
+namespace invalidation {
 
 // FCMSyncNetworkChannel implements common tasks needed from the network by
 // client:
@@ -96,6 +96,7 @@
 
   base::ObserverList<Observer>::Unchecked observers_;
 };
-}  // namespace syncer
+
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_FCM_SYNC_NETWORK_CHANNEL_H_
diff --git a/components/invalidation/impl/invalidation_logger.cc b/components/invalidation/impl/invalidation_logger.cc
index 3510f7b..030d1c5b 100644
--- a/components/invalidation/impl/invalidation_logger.cc
+++ b/components/invalidation/impl/invalidation_logger.cc
@@ -13,8 +13,7 @@
 namespace invalidation {
 
 InvalidationLogger::InvalidationLogger()
-    : last_invalidator_state_(syncer::TRANSIENT_INVALIDATION_ERROR),
-      last_invalidator_state_timestamp_(base::Time::Now()) { }
+    : last_invalidator_state_timestamp_(base::Time::Now()) {}
 
 InvalidationLogger::~InvalidationLogger() = default;
 
@@ -37,8 +36,7 @@
     observer.OnRegistrationChange(registered_handlers_);
 }
 
-void InvalidationLogger::OnStateChange(
-    const syncer::InvalidatorState& new_state) {
+void InvalidationLogger::OnStateChange(const InvalidatorState& new_state) {
   // Prevent spurious same state emissions from updating the timestamp.
   if (new_state != last_invalidator_state_)
     last_invalidator_state_timestamp_ = base::Time::Now();
@@ -54,7 +52,7 @@
 }
 
 void InvalidationLogger::OnUpdatedTopics(
-    std::map<std::string, syncer::Topics> handler_updated_topics_map) {
+    std::map<std::string, Topics> handler_updated_topics_map) {
   for (const auto& updated_topics : handler_updated_topics_map) {
     handler_latest_topics_map_[updated_topics.first] = updated_topics.second;
   }
@@ -63,9 +61,9 @@
 
 void InvalidationLogger::EmitUpdatedTopics() {
   for (const auto& handler_name_and_topics : handler_latest_topics_map_) {
-    syncer::TopicCountMap per_handler_invalidation_count;
+    TopicCountMap per_handler_invalidation_count;
     for (const auto& topic_item : handler_name_and_topics.second) {
-      const syncer::Topic& topic = topic_item.first;
+      const Topic& topic = topic_item.first;
       per_handler_invalidation_count[topic] = invalidation_count_[topic];
     }
     for (auto& observer : observer_list_) {
@@ -81,7 +79,7 @@
 }
 
 void InvalidationLogger::OnInvalidation(
-    const syncer::TopicInvalidationMap& invalidations) {
+    const TopicInvalidationMap& invalidations) {
   for (const auto& topic : invalidations.GetTopics()) {
     invalidation_count_[topic] += invalidations.ForTopic(topic).GetSize();
   }
@@ -109,4 +107,5 @@
     const InvalidationLoggerObserver* debug_observer) const {
   return observer_list_.HasObserver(debug_observer);
 }
+
 }  // namespace invalidation
diff --git a/components/invalidation/impl/invalidation_logger.h b/components/invalidation/impl/invalidation_logger.h
index 789eb94..c1fab8b 100644
--- a/components/invalidation/impl/invalidation_logger.h
+++ b/components/invalidation/impl/invalidation_logger.h
@@ -16,13 +16,10 @@
 class DictionaryValue;
 }  // namespace base
 
-namespace syncer {
-class TopicInvalidationMap;
-}  // namespace syncer
-
 namespace invalidation {
 
 class InvalidationLoggerObserver;
+class TopicInvalidationMap;
 
 // This class is in charge of logging invalidation-related information.
 // It is used store the state of the InvalidationService that owns this object
@@ -47,11 +44,11 @@
   // We will do local logging here too.
   void OnRegistration(const std::string& details);
   void OnUnregistration(const std::string& details);
-  void OnStateChange(const syncer::InvalidatorState& new_state);
+  void OnStateChange(const InvalidatorState& new_state);
   void OnUpdatedTopics(
-      std::map<std::string, syncer::Topics> handler_updated_topics_map);
+      std::map<std::string, Topics> handler_updated_topics_map);
   void OnDebugMessage(const base::DictionaryValue& details);
-  void OnInvalidation(const syncer::TopicInvalidationMap& invalidations);
+  void OnInvalidation(const TopicInvalidationMap& invalidations);
 
   // Triggers messages to be sent to the Observers to provide them with
   // the current state of the logging.
@@ -79,15 +76,15 @@
   base::ObserverList<InvalidationLoggerObserver>::Unchecked observer_list_;
 
   // The last InvalidatorState updated by the InvalidatorService.
-  syncer::InvalidatorState last_invalidator_state_;
+  InvalidatorState last_invalidator_state_ = TRANSIENT_INVALIDATION_ERROR;
   base::Time last_invalidator_state_timestamp_;
 
   // The map that contains every topic that is currently registered and its
   // owner.
-  std::map<std::string, syncer::Topics> handler_latest_topics_map_;
+  std::map<std::string, Topics> handler_latest_topics_map_;
 
   // The map that counts how many invalidations per Topic there has been.
-  syncer::TopicCountMap invalidation_count_;
+  TopicCountMap invalidation_count_;
 
   // The name of all invalidatorHandler registered (note that this is not
   // necessarily the same as the keys of latest_topics_, because they might
diff --git a/components/invalidation/impl/invalidation_logger_observer.h b/components/invalidation/impl/invalidation_logger_observer.h
index 7920949d..4b6d0a9 100644
--- a/components/invalidation/impl/invalidation_logger_observer.h
+++ b/components/invalidation/impl/invalidation_logger_observer.h
@@ -12,11 +12,10 @@
 class DictionaryValue;
 }  // namespace base
 
-namespace syncer {
-class TopicInvalidationMap;
-}  // namespace syncer
-
 namespace invalidation {
+
+class TopicInvalidationMap;
+
 // This class provides the possibility to register as an observer for the
 // InvalidationLogger notifications whenever an InvalidationService changes
 // its internal state.
@@ -25,12 +24,12 @@
  public:
   virtual void OnRegistrationChange(
       const std::multiset<std::string>& registered_handlers) = 0;
-  virtual void OnStateChange(const syncer::InvalidatorState& new_state,
+  virtual void OnStateChange(const InvalidatorState& new_state,
                              const base::Time& last_change_timestamp) = 0;
   virtual void OnUpdatedTopics(const std::string& handler_name,
-                               const syncer::TopicCountMap& details) = 0;
+                               const TopicCountMap& details) = 0;
   virtual void OnDebugMessage(const base::DictionaryValue& details) = 0;
-  virtual void OnInvalidation(const syncer::TopicInvalidationMap& details) = 0;
+  virtual void OnInvalidation(const TopicInvalidationMap& details) = 0;
   virtual void OnDetailedStatus(const base::DictionaryValue& details) = 0;
 
  protected:
diff --git a/components/invalidation/impl/invalidation_logger_unittest.cc b/components/invalidation/impl/invalidation_logger_unittest.cc
index 86073f0..b531041 100644
--- a/components/invalidation/impl/invalidation_logger_unittest.cc
+++ b/components/invalidation/impl/invalidation_logger_unittest.cc
@@ -22,7 +22,7 @@
     debug_message_received = false;
     invalidation_received = false;
     detailed_status_received = false;
-    updated_topics_replicated = std::map<std::string, syncer::TopicCountMap>();
+    updated_topics_replicated = std::map<std::string, TopicCountMap>();
     registered_handlers = std::multiset<std::string>();
   }
 
@@ -32,13 +32,13 @@
     registration_change_received = true;
   }
 
-  void OnStateChange(const syncer::InvalidatorState& new_state,
+  void OnStateChange(const InvalidatorState& new_state,
                      const base::Time& last_change_timestamp) override {
     state_received = true;
   }
 
   void OnUpdatedTopics(const std::string& handler,
-                       const syncer::TopicCountMap& topics_counts) override {
+                       const TopicCountMap& topics_counts) override {
     update_id_received = true;
     updated_topics_replicated[handler] = topics_counts;
   }
@@ -47,8 +47,7 @@
     debug_message_received = true;
   }
 
-  void OnInvalidation(
-      const syncer::TopicInvalidationMap& new_invalidations) override {
+  void OnInvalidation(const TopicInvalidationMap& new_invalidations) override {
     invalidation_received = true;
   }
 
@@ -62,7 +61,7 @@
   bool debug_message_received;
   bool invalidation_received;
   bool detailed_status_received;
-  std::map<std::string, syncer::TopicCountMap> updated_topics_replicated;
+  std::map<std::string, TopicCountMap> updated_topics_replicated;
   std::multiset<std::string> registered_handlers;
 };
 
@@ -73,7 +72,7 @@
   InvalidationLoggerObserverTest observer_test;
 
   log.RegisterObserver(&observer_test);
-  log.OnStateChange(syncer::INVALIDATIONS_ENABLED);
+  log.OnStateChange(INVALIDATIONS_ENABLED);
   EXPECT_TRUE(observer_test.state_received);
   EXPECT_FALSE(observer_test.update_id_received);
   EXPECT_FALSE(observer_test.registration_change_received);
@@ -83,7 +82,7 @@
 
   observer_test.ResetStates();
 
-  log.OnInvalidation(syncer::TopicInvalidationMap());
+  log.OnInvalidation(TopicInvalidationMap());
   EXPECT_TRUE(observer_test.invalidation_received);
   EXPECT_FALSE(observer_test.state_received);
   EXPECT_FALSE(observer_test.update_id_received);
@@ -104,12 +103,12 @@
   log.RegisterObserver(&observer_test);
   log.UnregisterObserver(&observer_test);
 
-  log.OnInvalidation(syncer::TopicInvalidationMap());
-  log.OnStateChange(syncer::INVALIDATIONS_ENABLED);
+  log.OnInvalidation(TopicInvalidationMap());
+  log.OnStateChange(INVALIDATIONS_ENABLED);
   log.OnRegistration(std::string());
   log.OnUnregistration(std::string());
   log.OnDebugMessage(base::DictionaryValue());
-  log.OnUpdatedTopics(std::map<std::string, syncer::Topics>());
+  log.OnUpdatedTopics(std::map<std::string, Topics>());
   EXPECT_FALSE(observer_test.registration_change_received);
   EXPECT_FALSE(observer_test.update_id_received);
   EXPECT_FALSE(observer_test.invalidation_received);
@@ -137,8 +136,8 @@
   EXPECT_FALSE(observer_test.detailed_status_received);
 
   observer_test.ResetStates();
-  std::map<std::string, syncer::Topics> test_map;
-  test_map["Test"] = syncer::Topics();
+  std::map<std::string, Topics> test_map;
+  test_map["Test"] = Topics();
   log.OnUpdatedTopics(test_map);
   EXPECT_TRUE(observer_test.update_id_received);
   observer_test.ResetStates();
@@ -160,26 +159,26 @@
 TEST(InvalidationLoggerTest, TestUpdatedTopicsMap) {
   InvalidationLogger log;
   InvalidationLoggerObserverTest observer_test;
-  std::map<std::string, syncer::Topics> send_test_map;
-  std::map<std::string, syncer::TopicCountMap> expected_received_map;
+  std::map<std::string, Topics> send_test_map;
+  std::map<std::string, TopicCountMap> expected_received_map;
   log.RegisterObserver(&observer_test);
 
-  syncer::Topics topics_a;
-  syncer::TopicCountMap topics_counts_a;
+  Topics topics_a;
+  TopicCountMap topics_counts_a;
 
-  syncer::Topic t1 = "Topic1";
-  topics_a.emplace(t1, syncer::TopicMetadata{/*is_public=*/false});
+  Topic t1 = "Topic1";
+  topics_a.emplace(t1, TopicMetadata{/*is_public=*/false});
   topics_counts_a[t1] = 0;
 
-  syncer::Topic t2 = "Topic2";
-  topics_a.emplace(t2, syncer::TopicMetadata{/*is_public=*/false});
+  Topic t2 = "Topic2";
+  topics_a.emplace(t2, TopicMetadata{/*is_public=*/false});
   topics_counts_a[t2] = 0;
 
-  syncer::Topics topics_b;
-  syncer::TopicCountMap topics_counts_b;
+  Topics topics_b;
+  TopicCountMap topics_counts_b;
 
-  syncer::Topic t3 = "Topic3";
-  topics_b.emplace(t3, syncer::TopicMetadata{/*is_public=*/false});
+  Topic t3 = "Topic3";
+  topics_b.emplace(t3, TopicMetadata{/*is_public=*/false});
   topics_counts_b[t3] = 0;
 
   send_test_map["TestA"] = topics_a;
@@ -191,15 +190,15 @@
   log.OnUpdatedTopics(send_test_map);
   EXPECT_EQ(expected_received_map, observer_test.updated_topics_replicated);
 
-  syncer::Topics topics_b2;
-  syncer::TopicCountMap topics_counts_b2;
+  Topics topics_b2;
+  TopicCountMap topics_counts_b2;
 
-  syncer::Topic t4 = "Topic4";
-  topics_b2.emplace(t4, syncer::TopicMetadata{/*is_public=*/false});
+  Topic t4 = "Topic4";
+  topics_b2.emplace(t4, TopicMetadata{/*is_public=*/false});
   topics_counts_b2[t4] = 0;
 
-  syncer::Topic t5 = "Topic5";
-  topics_b2.emplace(t5, syncer::TopicMetadata{/*is_public=*/false});
+  Topic t5 = "Topic5";
+  topics_b2.emplace(t5, TopicMetadata{/*is_public=*/false});
   topics_counts_b2[t5] = 0;
 
   send_test_map["TestB"] = topics_b2;
@@ -224,21 +223,21 @@
   InvalidationLoggerObserverTest observer_test;
   log.RegisterObserver(&observer_test);
 
-  std::map<std::string, syncer::Topics> send_test_map;
-  std::map<std::string, syncer::TopicCountMap> expected_received_map;
-  syncer::Topics topics;
-  syncer::TopicCountMap topics_counts;
+  std::map<std::string, Topics> send_test_map;
+  std::map<std::string, TopicCountMap> expected_received_map;
+  Topics topics;
+  TopicCountMap topics_counts;
 
-  syncer::Topic t1 = "Topic1";
-  topics.emplace(t1, syncer::TopicMetadata{/*is_public=*/false});
+  Topic t1 = "Topic1";
+  topics.emplace(t1, TopicMetadata{/*is_public=*/false});
   topics_counts[t1] = 1;
 
   // Generate invalidation for |t1| only.
-  syncer::TopicInvalidationMap fake_invalidations;
-  fake_invalidations.Insert(syncer::Invalidation::InitUnknownVersion(t1));
+  TopicInvalidationMap fake_invalidations;
+  fake_invalidations.Insert(Invalidation::InitUnknownVersion(t1));
 
-  syncer::Topic t2 = "Topic2";
-  topics.emplace(t2, syncer::TopicMetadata{/*is_public=*/false});
+  Topic t2 = "Topic2";
+  topics.emplace(t2, TopicMetadata{/*is_public=*/false});
   topics_counts[t2] = 0;
 
   // Register the two Topics and send an invalidation only for |t1|.
@@ -283,4 +282,5 @@
 
   log.UnregisterObserver(&observer_test);
 }
+
 }  // namespace invalidation
diff --git a/components/invalidation/impl/invalidation_service_test_template.cc b/components/invalidation/impl/invalidation_service_test_template.cc
index 74e82b83..d7f3e34 100644
--- a/components/invalidation/impl/invalidation_service_test_template.cc
+++ b/components/invalidation/impl/invalidation_service_test_template.cc
@@ -9,17 +9,17 @@
 BoundFakeInvalidationHandler::BoundFakeInvalidationHandler(
     const invalidation::InvalidationService& invalidator)
     : invalidator_(invalidator),
-      last_retrieved_state_(syncer::DEFAULT_INVALIDATION_ERROR) {}
+      last_retrieved_state_(invalidation::DEFAULT_INVALIDATION_ERROR) {}
 
 BoundFakeInvalidationHandler::~BoundFakeInvalidationHandler() = default;
 
-syncer::InvalidatorState
+invalidation::InvalidatorState
 BoundFakeInvalidationHandler::GetLastRetrievedState() const {
   return last_retrieved_state_;
 }
 
 void BoundFakeInvalidationHandler::OnInvalidatorStateChange(
-    syncer::InvalidatorState state) {
+    invalidation::InvalidatorState state) {
   FakeInvalidationHandler::OnInvalidatorStateChange(state);
   last_retrieved_state_ = invalidator_.GetInvalidatorState();
 }
diff --git a/components/invalidation/impl/invalidation_service_test_template.h b/components/invalidation/impl/invalidation_service_test_template.h
index 50dfae0e..572c15f 100644
--- a/components/invalidation/impl/invalidation_service_test_template.h
+++ b/components/invalidation/impl/invalidation_service_test_template.h
@@ -82,6 +82,11 @@
 #include "components/invalidation/public/topic_invalidation_map.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+// TODO(crbug.com/1031125): consider moving this file content under invalidation
+// namespace, instead of specifying it everywhere (invalidation::internal if
+// polluting invalidation namespace is a concern, though it already pollutes
+// global namespace).
+
 template <typename InvalidatorTestDelegate>
 class InvalidationServiceTest : public testing::Test {
  protected:
@@ -95,10 +100,10 @@
 
   InvalidatorTestDelegate delegate_;
 
-  const syncer::Topic topic1 = "BOOKMARK";
-  const syncer::Topic topic2 = "PREFERENCE";
-  const syncer::Topic topic3 = "AUTOFILL";
-  const syncer::Topic topic4 = "PUSH_MESSAGE";
+  const invalidation::Topic topic1 = "BOOKMARK";
+  const invalidation::Topic topic2 = "PREFERENCE";
+  const invalidation::Topic topic3 = "AUTOFILL";
+  const invalidation::Topic topic4 = "PUSH_MESSAGE";
 };
 
 TYPED_TEST_SUITE_P(InvalidationServiceTest);
@@ -111,33 +116,36 @@
   invalidation::InvalidationService* const invalidator =
       this->CreateAndInitializeInvalidationService();
 
-  syncer::FakeInvalidationHandler handler;
+  invalidation::FakeInvalidationHandler handler;
 
   invalidator->RegisterInvalidationHandler(&handler);
 
-  syncer::TopicInvalidationMap invalidation_map;
-  invalidation_map.Insert(syncer::Invalidation::Init(this->topic1, 1, "1"));
-  invalidation_map.Insert(syncer::Invalidation::Init(this->topic2, 2, "2"));
-  invalidation_map.Insert(syncer::Invalidation::Init(this->topic3, 3, "3"));
+  invalidation::TopicInvalidationMap invalidation_map;
+  invalidation_map.Insert(
+      invalidation::Invalidation::Init(this->topic1, 1, "1"));
+  invalidation_map.Insert(
+      invalidation::Invalidation::Init(this->topic2, 2, "2"));
+  invalidation_map.Insert(
+      invalidation::Invalidation::Init(this->topic3, 3, "3"));
 
   // Should be ignored since no IDs are registered to |handler|.
   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
   EXPECT_EQ(0, handler.GetInvalidationCount());
 
-  syncer::TopicSet topics;
+  invalidation::TopicSet topics;
   topics.insert(this->topic1);
   topics.insert(this->topic2);
   EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler, topics));
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
+      invalidation::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
 
-  syncer::TopicInvalidationMap expected_invalidations;
+  invalidation::TopicInvalidationMap expected_invalidations;
   expected_invalidations.Insert(
-      syncer::Invalidation::Init(this->topic1, 1, "1"));
+      invalidation::Invalidation::Init(this->topic1, 1, "1"));
   expected_invalidations.Insert(
-      syncer::Invalidation::Init(this->topic2, 2, "2"));
+      invalidation::Invalidation::Init(this->topic2, 2, "2"));
 
   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
   EXPECT_EQ(1, handler.GetInvalidationCount());
@@ -147,11 +155,11 @@
   topics.insert(this->topic3);
   EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler, topics));
 
-  expected_invalidations = syncer::TopicInvalidationMap();
+  expected_invalidations = invalidation::TopicInvalidationMap();
   expected_invalidations.Insert(
-      syncer::Invalidation::Init(this->topic2, 2, "2"));
+      invalidation::Invalidation::Init(this->topic2, 2, "2"));
   expected_invalidations.Insert(
-      syncer::Invalidation::Init(this->topic3, 3, "3"));
+      invalidation::Invalidation::Init(this->topic3, 3, "3"));
 
   // Removed Topics should not be notified, newly-added ones should.
   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
@@ -159,14 +167,13 @@
   EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap()));
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+      invalidation::TRANSIENT_INVALIDATION_ERROR);
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler.GetInvalidatorState());
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED,
-            handler.GetInvalidatorState());
+      invalidation::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
 
   invalidator->UnregisterInvalidationHandler(&handler);
 
@@ -184,10 +191,10 @@
   invalidation::InvalidationService* const invalidator =
       this->CreateAndInitializeInvalidationService();
 
-  syncer::FakeInvalidationHandler handler1;
-  syncer::FakeInvalidationHandler handler2;
-  syncer::FakeInvalidationHandler handler3;
-  syncer::FakeInvalidationHandler handler4;
+  invalidation::FakeInvalidationHandler handler1;
+  invalidation::FakeInvalidationHandler handler2;
+  invalidation::FakeInvalidationHandler handler3;
+  invalidation::FakeInvalidationHandler handler4;
 
   invalidator->RegisterInvalidationHandler(&handler1);
   invalidator->RegisterInvalidationHandler(&handler2);
@@ -195,14 +202,14 @@
   invalidator->RegisterInvalidationHandler(&handler4);
 
   {
-    syncer::TopicSet topics;
+    invalidation::TopicSet topics;
     topics.insert(this->topic1);
     topics.insert(this->topic2);
     EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler1, topics));
   }
 
   {
-    syncer::TopicSet topics;
+    invalidation::TopicSet topics;
     topics.insert(this->topic3);
     EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler2, topics));
   }
@@ -210,7 +217,7 @@
   // Don't register any topics for handler3.
 
   {
-    syncer::TopicSet topics;
+    invalidation::TopicSet topics;
     topics.insert(this->topic4);
     EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler4, topics));
   }
@@ -218,33 +225,40 @@
   invalidator->UnregisterInvalidationHandler(&handler4);
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler3.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+      invalidation::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED,
+            handler1.GetInvalidatorState());
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED,
+            handler2.GetInvalidatorState());
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED,
+            handler3.GetInvalidatorState());
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler4.GetInvalidatorState());
 
   {
-    syncer::TopicInvalidationMap invalidation_map;
-    invalidation_map.Insert(syncer::Invalidation::Init(this->topic1, 1, "1"));
-    invalidation_map.Insert(syncer::Invalidation::Init(this->topic2, 2, "2"));
-    invalidation_map.Insert(syncer::Invalidation::Init(this->topic3, 3, "3"));
-    invalidation_map.Insert(syncer::Invalidation::Init(this->topic4, 4, "4"));
+    invalidation::TopicInvalidationMap invalidation_map;
+    invalidation_map.Insert(
+        invalidation::Invalidation::Init(this->topic1, 1, "1"));
+    invalidation_map.Insert(
+        invalidation::Invalidation::Init(this->topic2, 2, "2"));
+    invalidation_map.Insert(
+        invalidation::Invalidation::Init(this->topic3, 3, "3"));
+    invalidation_map.Insert(
+        invalidation::Invalidation::Init(this->topic4, 4, "4"));
     this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
 
-    syncer::TopicInvalidationMap expected_invalidations;
+    invalidation::TopicInvalidationMap expected_invalidations;
     expected_invalidations.Insert(
-        syncer::Invalidation::Init(this->topic1, 1, "1"));
+        invalidation::Invalidation::Init(this->topic1, 1, "1"));
     expected_invalidations.Insert(
-        syncer::Invalidation::Init(this->topic2, 2, "2"));
+        invalidation::Invalidation::Init(this->topic2, 2, "2"));
 
     EXPECT_EQ(1, handler1.GetInvalidationCount());
     EXPECT_THAT(expected_invalidations, Eq(handler1.GetLastInvalidationMap()));
 
-    expected_invalidations = syncer::TopicInvalidationMap();
+    expected_invalidations = invalidation::TopicInvalidationMap();
     expected_invalidations.Insert(
-        syncer::Invalidation::Init(this->topic3, 3, "3"));
+        invalidation::Invalidation::Init(this->topic3, 3, "3"));
 
     EXPECT_EQ(1, handler2.GetInvalidationCount());
     EXPECT_THAT(expected_invalidations, Eq(handler2.GetLastInvalidationMap()));
@@ -254,14 +268,14 @@
   }
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+      invalidation::TRANSIENT_INVALIDATION_ERROR);
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler1.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler2.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler3.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler4.GetInvalidatorState());
 
   invalidator->UnregisterInvalidationHandler(&handler3);
@@ -275,15 +289,15 @@
   invalidation::InvalidationService* const invalidator =
       this->CreateAndInitializeInvalidationService();
 
-  syncer::FakeInvalidationHandler handler1;
-  syncer::FakeInvalidationHandler handler2;
+  invalidation::FakeInvalidationHandler handler1;
+  invalidation::FakeInvalidationHandler handler2;
 
   invalidator->RegisterInvalidationHandler(&handler1);
   invalidator->RegisterInvalidationHandler(&handler2);
 
   // Registering both handlers for the same topic. First call should succeed,
   // second should fail.
-  syncer::TopicSet topics;
+  invalidation::TopicSet topics;
   topics.insert(this->topic1);
   EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler1, topics));
   EXPECT_FALSE(invalidator->UpdateInterestedTopics(&handler2, topics));
@@ -298,23 +312,23 @@
   invalidation::InvalidationService* const invalidator =
       this->CreateAndInitializeInvalidationService();
 
-  syncer::FakeInvalidationHandler handler1;
+  invalidation::FakeInvalidationHandler handler1;
 
   // Control observer.
-  syncer::FakeInvalidationHandler handler2;
+  invalidation::FakeInvalidationHandler handler2;
 
   invalidator->RegisterInvalidationHandler(&handler1);
   invalidator->RegisterInvalidationHandler(&handler2);
 
   {
-    syncer::TopicSet topics;
+    invalidation::TopicSet topics;
     topics.insert(this->topic1);
     topics.insert(this->topic2);
     EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler1, topics));
   }
 
   {
-    syncer::TopicSet topics;
+    invalidation::TopicSet topics;
     topics.insert(this->topic3);
     EXPECT_TRUE(invalidator->UpdateInterestedTopics(&handler2, topics));
   }
@@ -322,28 +336,33 @@
   // Unregister the topics for the first observer. It should not receive any
   // further invalidations.
   EXPECT_TRUE(
-      invalidator->UpdateInterestedTopics(&handler1, syncer::TopicSet()));
+      invalidator->UpdateInterestedTopics(&handler1, invalidation::TopicSet()));
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
+      invalidation::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED,
+            handler1.GetInvalidatorState());
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED,
+            handler2.GetInvalidatorState());
 
   {
-    syncer::TopicInvalidationMap invalidation_map;
-    invalidation_map.Insert(syncer::Invalidation::Init(this->topic1, 1, "1"));
-    invalidation_map.Insert(syncer::Invalidation::Init(this->topic2, 2, "2"));
-    invalidation_map.Insert(syncer::Invalidation::Init(this->topic3, 3, "3"));
+    invalidation::TopicInvalidationMap invalidation_map;
+    invalidation_map.Insert(
+        invalidation::Invalidation::Init(this->topic1, 1, "1"));
+    invalidation_map.Insert(
+        invalidation::Invalidation::Init(this->topic2, 2, "2"));
+    invalidation_map.Insert(
+        invalidation::Invalidation::Init(this->topic3, 3, "3"));
     this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
     EXPECT_EQ(0, handler1.GetInvalidationCount());
     EXPECT_EQ(1, handler2.GetInvalidationCount());
   }
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+      invalidation::TRANSIENT_INVALIDATION_ERROR);
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler1.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler2.GetInvalidatorState());
 
   invalidator->UnregisterInvalidationHandler(&handler2);
@@ -355,7 +374,8 @@
 // A FakeInvalidationHandler that is "bound" to a specific
 // InvalidationService.  This is for cross-referencing state information with
 // the bound InvalidationService.
-class BoundFakeInvalidationHandler : public syncer::FakeInvalidationHandler {
+class BoundFakeInvalidationHandler
+    : public invalidation::FakeInvalidationHandler {
  public:
   explicit BoundFakeInvalidationHandler(
       const invalidation::InvalidationService& invalidator);
@@ -364,14 +384,14 @@
   // Returns the last return value of GetInvalidatorState() on the
   // bound invalidator from the last time the invalidator state
   // changed.
-  syncer::InvalidatorState GetLastRetrievedState() const;
+  invalidation::InvalidatorState GetLastRetrievedState() const;
 
   // InvalidationHandler implementation.
-  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  void OnInvalidatorStateChange(invalidation::InvalidatorState state) override;
 
  private:
   const invalidation::InvalidationService& invalidator_;
-  syncer::InvalidatorState last_retrieved_state_;
+  invalidation::InvalidatorState last_retrieved_state_;
 
   DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler);
 };
@@ -386,15 +406,16 @@
   invalidator->RegisterInvalidationHandler(&handler);
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::INVALIDATIONS_ENABLED);
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
-  EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetLastRetrievedState());
+      invalidation::INVALIDATIONS_ENABLED);
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
+  EXPECT_EQ(invalidation::INVALIDATIONS_ENABLED,
+            handler.GetLastRetrievedState());
 
   this->delegate_.TriggerOnInvalidatorStateChange(
-      syncer::TRANSIENT_INVALIDATION_ERROR);
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+      invalidation::TRANSIENT_INVALIDATION_ERROR);
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler.GetInvalidatorState());
-  EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR,
+  EXPECT_EQ(invalidation::TRANSIENT_INVALIDATION_ERROR,
             handler.GetLastRetrievedState());
 
   invalidator->UnregisterInvalidationHandler(&handler);
diff --git a/components/invalidation/impl/invalidation_test_util.cc b/components/invalidation/impl/invalidation_test_util.cc
index e718eb8..ad1d520 100644
--- a/components/invalidation/impl/invalidation_test_util.cc
+++ b/components/invalidation/impl/invalidation_test_util.cc
@@ -9,7 +9,7 @@
 #include "base/values.h"
 #include "components/invalidation/public/invalidation.h"
 
-namespace syncer {
+namespace invalidation {
 
 using ::testing::MakeMatcher;
 using ::testing::MatchResultListener;
@@ -108,4 +108,4 @@
   return MakeMatcher(new InvalidationEqMatcher(expected));
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/invalidation_test_util.h b/components/invalidation/impl/invalidation_test_util.h
index bd1ef114..f393be1 100644
--- a/components/invalidation/impl/invalidation_test_util.h
+++ b/components/invalidation/impl/invalidation_test_util.h
@@ -9,7 +9,7 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 
-namespace syncer {
+namespace invalidation {
 
 class AckHandle;
 class Invalidation;
@@ -21,6 +21,6 @@
 
 ::testing::Matcher<const Invalidation&> Eq(const Invalidation& expected);
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_INVALIDATION_TEST_UTIL_H_
diff --git a/components/invalidation/impl/invalidator_registrar_with_memory.cc b/components/invalidation/impl/invalidator_registrar_with_memory.cc
index 018b9d7..28f9446 100644
--- a/components/invalidation/impl/invalidator_registrar_with_memory.cc
+++ b/components/invalidation/impl/invalidator_registrar_with_memory.cc
@@ -18,7 +18,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/scoped_user_pref_update.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -42,11 +42,11 @@
   prefs->ClearPref(kTopicsToHandlerDeprecated);
 }
 
-base::Optional<invalidation::TopicData> FindAnyDuplicatedTopic(
-    const std::set<invalidation::TopicData>& lhs,
-    const std::set<invalidation::TopicData>& rhs) {
+base::Optional<TopicData> FindAnyDuplicatedTopic(
+    const std::set<TopicData>& lhs,
+    const std::set<TopicData>& rhs) {
   auto intersection =
-      base::STLSetIntersection<std::vector<invalidation::TopicData>>(lhs, rhs);
+      base::STLSetIntersection<std::vector<TopicData>>(lhs, rhs);
   if (!intersection.empty()) {
     return intersection[0];
   }
@@ -96,12 +96,12 @@
         continue;
       }
       handler_name_to_subscribed_topics_map_[handler->GetString()].insert(
-          invalidation::TopicData(topic_name, is_public->GetBool()));
+          TopicData(topic_name, is_public->GetBool()));
     } else if (it.second.is_string()) {
       std::string handler_name;
       it.second.GetAsString(&handler_name);
       handler_name_to_subscribed_topics_map_[handler_name].insert(
-          invalidation::TopicData(topic_name, false));
+          TopicData(topic_name, false));
     }
   }
 }
@@ -134,7 +134,7 @@
 
 bool InvalidatorRegistrarWithMemory::UpdateRegisteredTopics(
     InvalidationHandler* handler,
-    const std::set<invalidation::TopicData>& topics) {
+    const std::set<TopicData>& topics) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CHECK(handler);
   CHECK(handlers_.HasObserver(handler));
@@ -143,8 +143,7 @@
     return false;
   }
 
-  std::set<invalidation::TopicData> old_topics =
-      registered_handler_to_topics_map_[handler];
+  std::set<TopicData> old_topics = registered_handler_to_topics_map_[handler];
   if (topics.empty()) {
     registered_handler_to_topics_map_.erase(handler);
   } else {
@@ -158,8 +157,7 @@
   // requires GetOwnerName() to return unique value for each handler, which is
   // currently not the case for CloudPolicyInvalidator (see crbug.com/1049591).
   auto to_unregister =
-      base::STLSetDifference<std::set<invalidation::TopicData>>(old_topics,
-                                                                topics);
+      base::STLSetDifference<std::set<TopicData>>(old_topics, topics);
   ;
   for (const auto& topic : to_unregister) {
     pref_data->RemoveKey(topic.name);
@@ -183,17 +181,17 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto lookup = registered_handler_to_topics_map_.find(handler);
   return lookup != registered_handler_to_topics_map_.end()
-             ? invalidation::ConvertTopicSetToLegacyTopicMap(lookup->second)
+             ? ConvertTopicSetToLegacyTopicMap(lookup->second)
              : Topics();
 }
 
 Topics InvalidatorRegistrarWithMemory::GetAllSubscribedTopics() const {
-  std::set<invalidation::TopicData> subscribed_topics;
+  std::set<TopicData> subscribed_topics;
   for (const auto& handler_to_topic : handler_name_to_subscribed_topics_map_) {
     subscribed_topics.insert(handler_to_topic.second.begin(),
                              handler_to_topic.second.end());
   }
-  return invalidation::ConvertTopicSetToLegacyTopicMap(subscribed_topics);
+  return ConvertTopicSetToLegacyTopicMap(subscribed_topics);
 }
 
 void InvalidatorRegistrarWithMemory::DispatchInvalidationsToHandlers(
@@ -241,8 +239,7 @@
   std::map<std::string, Topics> names_to_topics;
   for (const auto& handler_and_topics : registered_handler_to_topics_map_) {
     names_to_topics[handler_and_topics.first->GetOwnerName()] =
-        invalidation::ConvertTopicSetToLegacyTopicMap(
-            handler_and_topics.second);
+        ConvertTopicSetToLegacyTopicMap(handler_and_topics.second);
   }
   return names_to_topics;
 }
@@ -255,13 +252,13 @@
 
 bool InvalidatorRegistrarWithMemory::HasDuplicateTopicRegistration(
     InvalidationHandler* handler,
-    const std::set<invalidation::TopicData>& topics) const {
+    const std::set<TopicData>& topics) const {
   for (const auto& handler_and_topics : registered_handler_to_topics_map_) {
     if (handler_and_topics.first == handler) {
       continue;
     }
 
-    if (base::Optional<invalidation::TopicData> duplicate =
+    if (base::Optional<TopicData> duplicate =
             FindAnyDuplicatedTopic(topics, handler_and_topics.second)) {
       DVLOG(1) << "Duplicate registration: trying to register "
                << duplicate->name << " for " << handler
@@ -287,4 +284,4 @@
   return return_value;
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/invalidator_registrar_with_memory.h b/components/invalidation/impl/invalidator_registrar_with_memory.h
index 64fc71f..5360b3641 100644
--- a/components/invalidation/impl/invalidator_registrar_with_memory.h
+++ b/components/invalidation/impl/invalidator_registrar_with_memory.h
@@ -21,7 +21,7 @@
 class PrefRegistrySimple;
 class PrefService;
 
-namespace syncer {
+namespace invalidation {
 
 // A helper class for FCMInvalidationService.  It helps keep track of registered
 // handlers and which topic registrations are associated with each handler.
@@ -62,7 +62,7 @@
   // Note that this also updates the *subscribed* topics - assuming that whoever
   // called this will also send (un)subscription requests to the server.
   bool UpdateRegisteredTopics(InvalidationHandler* handler,
-                              const std::set<invalidation::TopicData>& topics)
+                              const std::set<TopicData>& topics)
       WARN_UNUSED_RESULT;
 
   // Returns all topics currently registered to |handler|.
@@ -108,9 +108,8 @@
  private:
   // Checks if any of the |topics| is already registered for a *different*
   // handler than the given one.
-  bool HasDuplicateTopicRegistration(
-      InvalidationHandler* handler,
-      const std::set<invalidation::TopicData>& topics) const;
+  bool HasDuplicateTopicRegistration(InvalidationHandler* handler,
+                                     const std::set<TopicData>& topics) const;
 
   // Generate a Dictionary with all the debugging information.
   base::DictionaryValue CollectDebugData() const;
@@ -121,9 +120,9 @@
   // Note: When a handler is unregistered, its entry is removed from
   // |registered_handler_to_topics_map_| but NOT from
   // |handler_name_to_subscribed_topics_map_|.
-  std::map<InvalidationHandler*, std::set<invalidation::TopicData>>
+  std::map<InvalidationHandler*, std::set<TopicData>>
       registered_handler_to_topics_map_;
-  std::map<std::string, std::set<invalidation::TopicData>>
+  std::map<std::string, std::set<TopicData>>
       handler_name_to_subscribed_topics_map_;
 
   InvalidatorState state_;
@@ -136,6 +135,6 @@
   const std::string sender_id_;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_INVALIDATOR_REGISTRAR_WITH_MEMORY_H_
diff --git a/components/invalidation/impl/invalidator_registrar_with_memory_unittest.cc b/components/invalidation/impl/invalidator_registrar_with_memory_unittest.cc
index 6045b61..fcb1a081 100644
--- a/components/invalidation/impl/invalidator_registrar_with_memory_unittest.cc
+++ b/components/invalidation/impl/invalidator_registrar_with_memory_unittest.cc
@@ -15,7 +15,7 @@
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -24,9 +24,9 @@
 // between. The handler should only see invalidations when it's registered and
 // its topics are registered.
 TEST(InvalidatorRegistrarWithMemoryTest, Basic) {
-  const invalidation::TopicData kTopic1(/*name=*/"a", /*is_public=*/false);
-  const invalidation::TopicData kTopic2(/*name=*/"b", /*is_public=*/false);
-  const invalidation::TopicData kTopic3(/*name=*/"c", /*is_public=*/false);
+  const TopicData kTopic1(/*name=*/"a", /*is_public=*/false);
+  const TopicData kTopic2(/*name=*/"b", /*is_public=*/false);
+  const TopicData kTopic3(/*name=*/"c", /*is_public=*/false);
 
   TestingPrefServiceSimple pref_service;
   InvalidatorRegistrarWithMemory::RegisterProfilePrefs(pref_service.registry());
@@ -92,10 +92,10 @@
 // invalidations, and the ones that have registered topics should receive
 // invalidations for those topics.
 TEST(InvalidatorRegistrarWithMemoryTest, MultipleHandlers) {
-  const invalidation::TopicData kTopic1(/*name=*/"a", /*is_public=*/false);
-  const invalidation::TopicData kTopic2(/*name=*/"b", /*is_public=*/false);
-  const invalidation::TopicData kTopic3(/*name=*/"c", /*is_public=*/false);
-  const invalidation::TopicData kTopic4(/*name=*/"d", /*is_public=*/false);
+  const TopicData kTopic1(/*name=*/"a", /*is_public=*/false);
+  const TopicData kTopic2(/*name=*/"b", /*is_public=*/false);
+  const TopicData kTopic3(/*name=*/"c", /*is_public=*/false);
+  const TopicData kTopic4(/*name=*/"d", /*is_public=*/false);
 
   TestingPrefServiceSimple pref_service;
   InvalidatorRegistrarWithMemory::RegisterProfilePrefs(pref_service.registry());
@@ -165,7 +165,7 @@
 // Multiple registrations by different handlers on the same topic should
 // return false.
 TEST(InvalidatorRegistrarWithMemoryTest, MultipleRegistrations) {
-  const invalidation::TopicData kTopic1(/*name=*/"a", /*is_public=*/false);
+  const TopicData kTopic1(/*name=*/"a", /*is_public=*/false);
 
   TestingPrefServiceSimple pref_service;
   InvalidatorRegistrarWithMemory::RegisterProfilePrefs(pref_service.registry());
@@ -196,9 +196,9 @@
 // Make sure that passing an empty set to UpdateRegisteredTopics clears the
 // corresponding entries for the handler.
 TEST(InvalidatorRegistrarWithMemoryTest, EmptySetUnregisters) {
-  const invalidation::TopicData kTopic1(/*name=*/"a", /*is_public=*/false);
-  const invalidation::TopicData kTopic2(/*name=*/"b", /*is_public=*/false);
-  const invalidation::TopicData kTopic3(/*name=*/"c", /*is_public=*/false);
+  const TopicData kTopic1(/*name=*/"a", /*is_public=*/false);
+  const TopicData kTopic2(/*name=*/"b", /*is_public=*/false);
+  const TopicData kTopic3(/*name=*/"c", /*is_public=*/false);
 
   TestingPrefServiceSimple pref_service;
   InvalidatorRegistrarWithMemory::RegisterProfilePrefs(pref_service.registry());
@@ -246,4 +246,4 @@
 
 }  // namespace
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/mock_ack_handler.cc b/components/invalidation/impl/mock_ack_handler.cc
index d15951de..9a1f4f60 100644
--- a/components/invalidation/impl/mock_ack_handler.cc
+++ b/components/invalidation/impl/mock_ack_handler.cc
@@ -10,22 +10,21 @@
 #include "components/invalidation/public/ack_handle.h"
 #include "components/invalidation/public/invalidation.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
 struct AckHandleMatcher {
   explicit AckHandleMatcher(const AckHandle& handle);
-  bool operator()(const syncer::Invalidation& invalidation) const;
+  bool operator()(const Invalidation& invalidation) const;
 
-  syncer::AckHandle handle_;
+  AckHandle handle_;
 };
 
 AckHandleMatcher::AckHandleMatcher(const AckHandle& handle)
   : handle_(handle) {}
 
-bool AckHandleMatcher::operator()(
-    const syncer::Invalidation& invalidation) const {
+bool AckHandleMatcher::operator()(const Invalidation& invalidation) const {
   return handle_.Equals(invalidation.ack_handle());
 }
 
@@ -103,4 +102,4 @@
   unrecovered_drop_events_.emplace(topic, handle);
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/mock_ack_handler.h b/components/invalidation/impl/mock_ack_handler.h
index 2c1e230..280839c 100644
--- a/components/invalidation/impl/mock_ack_handler.h
+++ b/components/invalidation/impl/mock_ack_handler.h
@@ -14,7 +14,7 @@
 #include "components/invalidation/public/invalidation_export.h"
 #include "components/invalidation/public/invalidation_util.h"
 
-namespace syncer {
+namespace invalidation {
 
 class Invalidation;
 
@@ -59,7 +59,7 @@
   void Drop(const Topic& topic, const AckHandle& handle) override;
 
  private:
-  typedef std::vector<syncer::Invalidation> InvalidationVector;
+  typedef std::vector<Invalidation> InvalidationVector;
 
   InvalidationVector unsent_invalidations_;
   InvalidationVector unacked_invalidations_;
@@ -69,6 +69,6 @@
   std::map<Topic, AckHandle> unrecovered_drop_events_;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_MOCK_ACK_HANDLER_H_
diff --git a/components/invalidation/impl/per_user_topic_subscription_manager.cc b/components/invalidation/impl/per_user_topic_subscription_manager.cc
index 2c8adc32..93c8a967 100644
--- a/components/invalidation/impl/per_user_topic_subscription_manager.cc
+++ b/components/invalidation/impl/per_user_topic_subscription_manager.cc
@@ -28,7 +28,7 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "google_apis/gaia/gaia_constants.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -208,7 +208,7 @@
 }
 
 PerUserTopicSubscriptionManager::PerUserTopicSubscriptionManager(
-    invalidation::IdentityProvider* identity_provider,
+    IdentityProvider* identity_provider,
     PrefService* pref_service,
     network::mojom::URLLoaderFactory* url_loader_factory,
     const std::string& project_id,
@@ -225,7 +225,7 @@
 // static
 std::unique_ptr<PerUserTopicSubscriptionManager>
 PerUserTopicSubscriptionManager::Create(
-    invalidation::IdentityProvider* identity_provider,
+    IdentityProvider* identity_provider,
     PrefService* pref_service,
     network::mojom::URLLoaderFactory* url_loader_factory,
     const std::string& project_id,
@@ -636,4 +636,4 @@
   return it->second;
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/per_user_topic_subscription_manager.h b/components/invalidation/impl/per_user_topic_subscription_manager.h
index 6036fa00..ceae081 100644
--- a/components/invalidation/impl/per_user_topic_subscription_manager.h
+++ b/components/invalidation/impl/per_user_topic_subscription_manager.h
@@ -28,7 +28,7 @@
 class IdentityProvider;
 }  // namespace invalidation
 
-namespace syncer {
+namespace invalidation {
 
 // A class that manages the subscription to topics for server-issued
 // notifications.
@@ -44,7 +44,7 @@
   };
 
   PerUserTopicSubscriptionManager(
-      invalidation::IdentityProvider* identity_provider,
+      IdentityProvider* identity_provider,
       PrefService* pref_service,
       network::mojom::URLLoaderFactory* url_loader_factory,
       const std::string& project_id,
@@ -57,7 +57,7 @@
 
   // Just calls std::make_unique. For ease of base::Bind'ing
   static std::unique_ptr<PerUserTopicSubscriptionManager> Create(
-      invalidation::IdentityProvider* identity_provider,
+      IdentityProvider* identity_provider,
       PrefService* pref_service,
       network::mojom::URLLoaderFactory* url_loader_factory,
       const std::string& project_id,
@@ -138,7 +138,7 @@
       SubscriptionChannelState invalidator_state);
 
   PrefService* const pref_service_;
-  invalidation::IdentityProvider* const identity_provider_;
+  IdentityProvider* const identity_provider_;
   network::mojom::URLLoaderFactory* const url_loader_factory_;
 
   const std::string project_id_;
@@ -159,8 +159,7 @@
 
   // Cached OAuth2 access token, and/or pending request to fetch one.
   std::string access_token_;
-  std::unique_ptr<invalidation::ActiveAccountAccessTokenFetcher>
-      access_token_fetcher_;
+  std::unique_ptr<ActiveAccountAccessTokenFetcher> access_token_fetcher_;
   base::OneShotTimer request_access_token_retry_timer_;
   net::BackoffEntry request_access_token_backoff_;
 
@@ -171,6 +170,6 @@
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_PER_USER_TOPIC_SUBSCRIPTION_MANAGER_H_
diff --git a/components/invalidation/impl/per_user_topic_subscription_manager_unittest.cc b/components/invalidation/impl/per_user_topic_subscription_manager_unittest.cc
index 3f748a8..ac2fa582 100644
--- a/components/invalidation/impl/per_user_topic_subscription_manager_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_subscription_manager_unittest.cc
@@ -31,7 +31,7 @@
 using testing::Not;
 using testing::SizeIs;
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -143,9 +143,8 @@
     AccountInfo account =
         identity_test_env_.MakePrimaryAccountAvailable("example@gmail.com");
     identity_test_env_.SetAutomaticIssueOfAccessTokens(true);
-    identity_provider_ =
-        std::make_unique<invalidation::ProfileIdentityProvider>(
-            identity_test_env_.identity_manager());
+    identity_provider_ = std::make_unique<ProfileIdentityProvider>(
+        identity_test_env_.identity_manager());
     identity_provider_->SetActiveAccountId(account.account_id);
   }
 
@@ -213,7 +212,7 @@
   TestingPrefServiceSimple pref_service_;
 
   signin::IdentityTestEnvironment identity_test_env_;
-  std::unique_ptr<invalidation::ProfileIdentityProvider> identity_provider_;
+  std::unique_ptr<ProfileIdentityProvider> identity_provider_;
 
   RegistrationManagerStateObserver state_observer_;
 };
@@ -863,4 +862,4 @@
       per_user_topic_subscription_manager->HaveAllRequestsFinishedForTest());
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/per_user_topic_subscription_request.cc b/components/invalidation/impl/per_user_topic_subscription_request.cc
index b7a5179..24f2ef23 100644
--- a/components/invalidation/impl/per_user_topic_subscription_request.cc
+++ b/components/invalidation/impl/per_user_topic_subscription_request.cc
@@ -20,6 +20,8 @@
 
 using net::HttpRequestHeaders;
 
+namespace invalidation {
+
 namespace {
 
 const char kPublicTopicNameKey[] = "publicTopicName";
@@ -54,25 +56,24 @@
   kMaxValue = kFailure,
 };
 
-void RecordRequestStatus(
-    SubscriptionStatus status,
-    syncer::PerUserTopicSubscriptionRequest::RequestType type,
-    const std::string& topic,
-    int net_error = net::OK,
-    int response_code = 200) {
+void RecordRequestStatus(SubscriptionStatus status,
+                         PerUserTopicSubscriptionRequest::RequestType type,
+                         const std::string& topic,
+                         int net_error = net::OK,
+                         int response_code = 200) {
   switch (type) {
-    case syncer::PerUserTopicSubscriptionRequest::SUBSCRIBE: {
+    case PerUserTopicSubscriptionRequest::SUBSCRIBE: {
       base::UmaHistogramEnumeration(
           "FCMInvalidations.SubscriptionRequestStatus", status);
       break;
     }
-    case syncer::PerUserTopicSubscriptionRequest::UNSUBSCRIBE: {
+    case PerUserTopicSubscriptionRequest::UNSUBSCRIBE: {
       base::UmaHistogramEnumeration(
           "FCMInvalidations.UnsubscriptionRequestStatus", status);
       break;
     }
   }
-  if (type != syncer::PerUserTopicSubscriptionRequest::SUBSCRIBE) {
+  if (type != PerUserTopicSubscriptionRequest::SUBSCRIBE) {
     return;
   }
 
@@ -102,8 +103,6 @@
 
 }  // namespace
 
-namespace syncer {
-
 PerUserTopicSubscriptionRequest::PerUserTopicSubscriptionRequest() = default;
 
 PerUserTopicSubscriptionRequest::~PerUserTopicSubscriptionRequest() = default;
@@ -409,4 +408,4 @@
   return url_loader;
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/per_user_topic_subscription_request.h b/components/invalidation/impl/per_user_topic_subscription_request.h
index 9e8ac62..d5fa19f 100644
--- a/components/invalidation/impl/per_user_topic_subscription_request.h
+++ b/components/invalidation/impl/per_user_topic_subscription_request.h
@@ -21,7 +21,7 @@
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
-namespace syncer {
+namespace invalidation {
 
 constexpr base::Feature kInvalidationsSkipUnsubscription{
     "InvalidationsSkipUnsubscription", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -131,6 +131,6 @@
   base::WeakPtrFactory<PerUserTopicSubscriptionRequest> weak_ptr_factory_{this};
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_PER_USER_TOPIC_SUBSCRIPTION_REQUEST_H_
diff --git a/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc b/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
index a7f8e6b1..fe56dd8 100644
--- a/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
@@ -22,7 +22,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -379,4 +379,4 @@
                                          net::HTTP_FORBIDDEN,
                                          net::HTTP_NOT_FOUND));
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/single_object_invalidation_set_unittest.cc b/components/invalidation/impl/single_object_invalidation_set_unittest.cc
index d8541b9..eac96b9 100644
--- a/components/invalidation/impl/single_object_invalidation_set_unittest.cc
+++ b/components/invalidation/impl/single_object_invalidation_set_unittest.cc
@@ -9,7 +9,7 @@
 #include "components/invalidation/impl/invalidation_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -74,4 +74,4 @@
 
 }  // namespace
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/status.cc b/components/invalidation/impl/status.cc
index aeef779d..22ee44a9 100644
--- a/components/invalidation/impl/status.cc
+++ b/components/invalidation/impl/status.cc
@@ -4,7 +4,7 @@
 
 #include "components/invalidation/impl/status.h"
 
-namespace syncer {
+namespace invalidation {
 
 Status::Status(StatusCode status_code, const std::string& message)
     : code(status_code), message(message) {}
@@ -15,4 +15,4 @@
 
 Status::~Status() = default;
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/status.h b/components/invalidation/impl/status.h
index 6b766ae..ad9f528 100644
--- a/components/invalidation/impl/status.h
+++ b/components/invalidation/impl/status.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-namespace syncer {
+namespace invalidation {
 
 // Status of the message arrived from FCM.
 // Used by UMA histogram, so entries shouldn't be reordered or removed.
@@ -55,6 +55,6 @@
   // Copy and assignment allowed.
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_STATUS_H_
diff --git a/components/invalidation/impl/topic_invalidation_map_test_util.cc b/components/invalidation/impl/topic_invalidation_map_test_util.cc
index a67f5c6..dae21b41 100644
--- a/components/invalidation/impl/topic_invalidation_map_test_util.cc
+++ b/components/invalidation/impl/topic_invalidation_map_test_util.cc
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 
-namespace syncer {
+namespace invalidation {
 
 using ::testing::MakeMatcher;
 using ::testing::Matcher;
@@ -46,14 +46,14 @@
 bool TopicInvalidationMapEqMatcher::MatchAndExplain(
     const TopicInvalidationMap& actual,
     MatchResultListener* listener) const {
-  std::vector<syncer::Invalidation> expected_invalidations;
-  std::vector<syncer::Invalidation> actual_invalidations;
+  std::vector<Invalidation> expected_invalidations;
+  std::vector<Invalidation> actual_invalidations;
 
   expected_.GetAllInvalidations(&expected_invalidations);
   actual.GetAllInvalidations(&actual_invalidations);
 
-  std::vector<syncer::Invalidation> expected_only;
-  std::vector<syncer::Invalidation> actual_only;
+  std::vector<Invalidation> expected_only;
+  std::vector<Invalidation> actual_only;
 
   for (const auto& expected_invalidation : expected_invalidations) {
     if (std::find_if(actual_invalidations.begin(), actual_invalidations.end(),
@@ -110,4 +110,4 @@
   return MakeMatcher(new TopicInvalidationMapEqMatcher(expected));
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/topic_invalidation_map_test_util.h b/components/invalidation/impl/topic_invalidation_map_test_util.h
index 1fdf704b..f82a9eb 100644
--- a/components/invalidation/impl/topic_invalidation_map_test_util.h
+++ b/components/invalidation/impl/topic_invalidation_map_test_util.h
@@ -10,11 +10,11 @@
 #include "components/invalidation/public/topic_invalidation_map.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-namespace syncer {
+namespace invalidation {
 
 ::testing::Matcher<const TopicInvalidationMap&> Eq(
     const TopicInvalidationMap& expected);
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_TOPIC_INVALIDATION_MAP_TEST_UTIL_H_
diff --git a/components/invalidation/impl/topic_invalidation_map_unittest.cc b/components/invalidation/impl/topic_invalidation_map_unittest.cc
index 51f876f..da38b39 100644
--- a/components/invalidation/impl/topic_invalidation_map_unittest.cc
+++ b/components/invalidation/impl/topic_invalidation_map_unittest.cc
@@ -8,7 +8,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -82,4 +82,4 @@
 
 }  // namespace
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/unacked_invalidation_set.cc b/components/invalidation/impl/unacked_invalidation_set.cc
index 06445f9..9b6eaec 100644
--- a/components/invalidation/impl/unacked_invalidation_set.cc
+++ b/components/invalidation/impl/unacked_invalidation_set.cc
@@ -8,7 +8,7 @@
 #include "components/invalidation/public/ack_handle.h"
 #include "components/invalidation/public/topic_invalidation_map.h"
 
-namespace syncer {
+namespace invalidation {
 
 const size_t UnackedInvalidationSet::kMaxBufferedInvalidations = 5;
 
@@ -128,4 +128,4 @@
   invalidations_.insert(unknown_version);
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/impl/unacked_invalidation_set.h b/components/invalidation/impl/unacked_invalidation_set.h
index f5e2183b..12eb3c8 100644
--- a/components/invalidation/impl/unacked_invalidation_set.h
+++ b/components/invalidation/impl/unacked_invalidation_set.h
@@ -16,7 +16,7 @@
 #include "components/invalidation/public/invalidation_export.h"
 #include "components/invalidation/public/invalidation_util.h"
 
-namespace syncer {
+namespace invalidation {
 
 class SingleObjectInvalidationSet;
 class TopicInvalidationMap;
@@ -103,6 +103,6 @@
   InvalidationsSet invalidations_;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_IMPL_UNACKED_INVALIDATION_SET_H_
diff --git a/components/invalidation/impl/unacked_invalidation_set_unittest.cc b/components/invalidation/impl/unacked_invalidation_set_unittest.cc
index df56ae7..71b168e 100644
--- a/components/invalidation/impl/unacked_invalidation_set_unittest.cc
+++ b/components/invalidation/impl/unacked_invalidation_set_unittest.cc
@@ -15,7 +15,7 @@
 #include "components/invalidation/public/topic_invalidation_map.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace syncer {
+namespace invalidation {
 
 class UnackedInvalidationSetTest : public testing::Test {
  public:
@@ -185,4 +185,4 @@
 
 }  // namespace
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/public/ack_handle.cc b/components/invalidation/public/ack_handle.cc
index 6beda62..5c7e585c 100644
--- a/components/invalidation/public/ack_handle.cc
+++ b/components/invalidation/public/ack_handle.cc
@@ -11,7 +11,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 // Hopefully enough bytes for uniqueness.
@@ -69,4 +69,4 @@
 
 AckHandle::~AckHandle() = default;
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/public/ack_handle.h b/components/invalidation/public/ack_handle.h
index beaa324c..8ada6702 100644
--- a/components/invalidation/public/ack_handle.h
+++ b/components/invalidation/public/ack_handle.h
@@ -15,7 +15,7 @@
 class DictionaryValue;
 }
 
-namespace syncer {
+namespace invalidation {
 
 // Opaque class that represents a local ack handle. We don't reuse the
 // invalidation ack handles to avoid unnecessary dependencies.
@@ -43,6 +43,6 @@
   base::Time timestamp_;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_ACK_HANDLE_H_
diff --git a/components/invalidation/public/ack_handler.h b/components/invalidation/public/ack_handler.h
index cabffb0..9702d33d 100644
--- a/components/invalidation/public/ack_handler.h
+++ b/components/invalidation/public/ack_handler.h
@@ -10,7 +10,7 @@
 #include "components/invalidation/public/invalidation_export.h"
 #include "components/invalidation/public/invalidation_util.h"
 
-namespace syncer {
+namespace invalidation {
 
 class AckHandle;
 
@@ -30,6 +30,6 @@
   virtual void Drop(const Topic& topic, const AckHandle& handle) = 0;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_ACK_HANDLER_H_
diff --git a/components/invalidation/public/invalidation.cc b/components/invalidation/public/invalidation.cc
index 4c95b1e..12467a9 100644
--- a/components/invalidation/public/invalidation.cc
+++ b/components/invalidation/public/invalidation.cc
@@ -16,7 +16,7 @@
 #include "components/invalidation/public/ack_handler.h"
 #include "components/invalidation/public/invalidation_util.h"
 
-namespace syncer {
+namespace invalidation {
 
 namespace {
 
@@ -156,4 +156,4 @@
       payload_(payload),
       ack_handle_(ack_handle) {}
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/public/invalidation.h b/components/invalidation/public/invalidation.h
index 57835cda..611e265 100644
--- a/components/invalidation/public/invalidation.h
+++ b/components/invalidation/public/invalidation.h
@@ -17,7 +17,7 @@
 #include "components/invalidation/public/invalidation_export.h"
 #include "components/invalidation/public/invalidation_util.h"
 
-namespace syncer {
+namespace invalidation {
 
 class AckHandler;
 
@@ -121,6 +121,6 @@
   scoped_refptr<base::SequencedTaskRunner> ack_handler_task_runner_;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_INVALIDATION_H_
diff --git a/components/invalidation/public/invalidation_handler.cc b/components/invalidation/public/invalidation_handler.cc
index 5cbdd12..f5f974f3 100644
--- a/components/invalidation/public/invalidation_handler.cc
+++ b/components/invalidation/public/invalidation_handler.cc
@@ -4,7 +4,7 @@
 
 #include "components/invalidation/public/invalidation_handler.h"
 
-namespace syncer {
+namespace invalidation {
 
 void InvalidationHandler::OnInvalidatorClientIdChange(
     const std::string& client_id) {}
@@ -13,4 +13,4 @@
   return false;
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/public/invalidation_handler.h b/components/invalidation/public/invalidation_handler.h
index c5aca3a8..0ac1903 100644
--- a/components/invalidation/public/invalidation_handler.h
+++ b/components/invalidation/public/invalidation_handler.h
@@ -11,7 +11,7 @@
 #include "components/invalidation/public/invalidation_util.h"
 #include "components/invalidation/public/invalidator_state.h"
 
-namespace syncer {
+namespace invalidation {
 
 class TopicInvalidationMap;
 
@@ -44,6 +44,6 @@
   virtual bool IsPublicTopic(const Topic& topic) const;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_INVALIDATION_HANDLER_H_
diff --git a/components/invalidation/public/invalidation_service.h b/components/invalidation/public/invalidation_service.h
index 9f84980..9844161 100644
--- a/components/invalidation/public/invalidation_service.h
+++ b/components/invalidation/public/invalidation_service.h
@@ -9,11 +9,9 @@
 #include "components/invalidation/public/invalidation_util.h"
 #include "components/invalidation/public/invalidator_state.h"
 
-namespace syncer {
-class InvalidationHandler;
-}  // namespace syncer
-
 namespace invalidation {
+
+class InvalidationHandler;
 class InvalidationLogger;
 
 // Interface for classes that handle invalidation subscriptions and send out
@@ -72,8 +70,7 @@
   // and it must not already be registered.
   //
   // Handler registrations are persisted across restarts of sync.
-  virtual void RegisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) = 0;
+  virtual void RegisterInvalidationHandler(InvalidationHandler* handler) = 0;
 
   // Updates the set of topics associated with |handler|. |handler| must not be
   // nullptr, and must already be registered. A topic must be subscribed for at
@@ -81,8 +78,8 @@
   // InvalidationHandler function returns false.
   //
   // Subscribed topics are persisted across restarts of sync.
-  virtual bool UpdateInterestedTopics(syncer::InvalidationHandler* handler,
-                                      const syncer::TopicSet& topics)
+  virtual bool UpdateInterestedTopics(InvalidationHandler* handler,
+                                      const TopicSet& topics)
       WARN_UNUSED_RESULT = 0;
 
   // Stops sending notifications to |handler|.  |handler| must not be NULL, and
@@ -90,13 +87,12 @@
   // associated with |handler|.
   //
   // Handler registrations are persisted across restarts of sync.
-  virtual void UnregisterInvalidationHandler(
-      syncer::InvalidationHandler* handler) = 0;
+  virtual void UnregisterInvalidationHandler(InvalidationHandler* handler) = 0;
 
   // Returns the current invalidator state.  When called from within
   // InvalidationHandler::OnInvalidatorStateChange(), this must return
   // the updated state.
-  virtual syncer::InvalidatorState GetInvalidatorState() const = 0;
+  virtual InvalidatorState GetInvalidatorState() const = 0;
 
   // Returns the ID belonging to this invalidation client.  Can be used to
   // prevent the receipt of notifications of our own changes.
diff --git a/components/invalidation/public/invalidation_util.cc b/components/invalidation/public/invalidation_util.cc
index 00388c58e..f8ec39c1 100644
--- a/components/invalidation/public/invalidation_util.cc
+++ b/components/invalidation/public/invalidation_util.cc
@@ -14,7 +14,7 @@
 #include "components/invalidation/public/invalidation.h"
 #include "components/invalidation/public/invalidation_handler.h"
 
-namespace syncer {
+namespace invalidation {
 
 bool InvalidationVersionLessThan::operator()(const Invalidation& a,
                                              const Invalidation& b) const {
@@ -61,4 +61,4 @@
   return HandlerOwnerType::kUnknown;
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/public/invalidation_util.h b/components/invalidation/public/invalidation_util.h
index 9a4f612..95704ab 100644
--- a/components/invalidation/public/invalidation_util.h
+++ b/components/invalidation/public/invalidation_util.h
@@ -17,7 +17,7 @@
 #include "base/values.h"
 #include "components/invalidation/public/invalidation_export.h"
 
-namespace syncer {
+namespace invalidation {
 
 // Used by UMA histogram, so entries shouldn't be reordered or removed.
 enum class HandlerOwnerType {
@@ -58,6 +58,6 @@
 
 HandlerOwnerType OwnerNameToHandlerType(const std::string& owner_name);
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_INVALIDATION_UTIL_H_
diff --git a/components/invalidation/public/invalidator_state.cc b/components/invalidation/public/invalidator_state.cc
index 6a57c06..35a145f 100644
--- a/components/invalidation/public/invalidator_state.cc
+++ b/components/invalidation/public/invalidator_state.cc
@@ -4,8 +4,7 @@
 
 #include "components/invalidation/public/invalidator_state.h"
 
-
-namespace syncer {
+namespace invalidation {
 
 const char* InvalidatorStateToString(InvalidatorState state) {
   switch (state) {
@@ -22,4 +21,4 @@
   }
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/public/invalidator_state.h b/components/invalidation/public/invalidator_state.h
index 27f4062..c7a776a 100644
--- a/components/invalidation/public/invalidator_state.h
+++ b/components/invalidation/public/invalidator_state.h
@@ -7,7 +7,7 @@
 
 #include "components/invalidation/public/invalidation_export.h"
 
-namespace syncer {
+namespace invalidation {
 
 enum InvalidatorState {
   // Invalidations are fully working.
@@ -32,6 +32,6 @@
 INVALIDATION_EXPORT const char* InvalidatorStateToString(
     InvalidatorState state);
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_INVALIDATOR_STATE_H_
diff --git a/components/invalidation/public/single_object_invalidation_set.cc b/components/invalidation/public/single_object_invalidation_set.cc
index 2c24fe3..03af1bc 100644
--- a/components/invalidation/public/single_object_invalidation_set.cc
+++ b/components/invalidation/public/single_object_invalidation_set.cc
@@ -7,7 +7,7 @@
 #include "base/values.h"
 #include "components/invalidation/public/invalidation_util.h"
 
-namespace syncer {
+namespace invalidation {
 
 SingleObjectInvalidationSet::SingleObjectInvalidationSet() = default;
 
@@ -99,4 +99,4 @@
   return value;
 }
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/public/single_object_invalidation_set.h b/components/invalidation/public/single_object_invalidation_set.h
index efce5093..08ad365c 100644
--- a/components/invalidation/public/single_object_invalidation_set.h
+++ b/components/invalidation/public/single_object_invalidation_set.h
@@ -18,7 +18,7 @@
 class ListValue;
 }  // namespace base
 
-namespace syncer {
+namespace invalidation {
 
 // Holds a list of invalidations that all share the same Topic.
 //
@@ -63,6 +63,6 @@
   InvalidationsSet invalidations_;
 };
 
-}  // syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_SINGLE_OBJECT_INVALIDATION_SET_H_
diff --git a/components/invalidation/public/topic_data.cc b/components/invalidation/public/topic_data.cc
index f1c9c67..2453394 100644
--- a/components/invalidation/public/topic_data.cc
+++ b/components/invalidation/public/topic_data.cc
@@ -31,12 +31,10 @@
   return lhs.is_public < rhs.is_public;
 }
 
-syncer::Topics ConvertTopicSetToLegacyTopicMap(
-    const std::set<TopicData>& topics) {
-  syncer::Topics result;
+Topics ConvertTopicSetToLegacyTopicMap(const std::set<TopicData>& topics) {
+  Topics result;
   for (const TopicData& topic : topics) {
-    result.emplace(topic.name,
-                   syncer::TopicMetadata{/*is_public=*/topic.is_public});
+    result.emplace(topic.name, TopicMetadata{/*is_public=*/topic.is_public});
   }
   return result;
 }
diff --git a/components/invalidation/public/topic_data.h b/components/invalidation/public/topic_data.h
index cd20024b..0c420e2 100644
--- a/components/invalidation/public/topic_data.h
+++ b/components/invalidation/public/topic_data.h
@@ -43,8 +43,7 @@
 
 // TDOO(crbug.com/1029698): delete this function together with legacy topic
 // datatypes.
-syncer::Topics ConvertTopicSetToLegacyTopicMap(
-    const std::set<TopicData>& topics);
+Topics ConvertTopicSetToLegacyTopicMap(const std::set<TopicData>& topics);
 
 }  // namespace invalidation
 
diff --git a/components/invalidation/public/topic_invalidation_map.cc b/components/invalidation/public/topic_invalidation_map.cc
index 7b91568..f02de18f 100644
--- a/components/invalidation/public/topic_invalidation_map.cc
+++ b/components/invalidation/public/topic_invalidation_map.cc
@@ -8,7 +8,7 @@
 
 #include "base/values.h"
 
-namespace syncer {
+namespace invalidation {
 
 TopicInvalidationMap::TopicInvalidationMap() = default;
 
@@ -68,7 +68,7 @@
 }
 
 void TopicInvalidationMap::GetAllInvalidations(
-    std::vector<syncer::Invalidation>* out) const {
+    std::vector<Invalidation>* out) const {
   for (const auto& topic_to_invalidations : map_) {
     out->insert(out->begin(), topic_to_invalidations.second.begin(),
                 topic_to_invalidations.second.end());
@@ -101,4 +101,4 @@
     const std::map<Topic, SingleObjectInvalidationSet>& map)
     : map_(map) {}
 
-}  // namespace syncer
+}  // namespace invalidation
diff --git a/components/invalidation/public/topic_invalidation_map.h b/components/invalidation/public/topic_invalidation_map.h
index b871ae2..c55a901 100644
--- a/components/invalidation/public/topic_invalidation_map.h
+++ b/components/invalidation/public/topic_invalidation_map.h
@@ -18,7 +18,7 @@
 class ListValue;
 }  // namespace base
 
-namespace syncer {
+namespace invalidation {
 
 // A set of notifications with some helper methods to organize them by Topic
 // and version number.
@@ -55,7 +55,7 @@
   const SingleObjectInvalidationSet& ForTopic(Topic topic) const;
 
   // Returns the contents of this map in a single vector.
-  void GetAllInvalidations(std::vector<syncer::Invalidation>* out) const;
+  void GetAllInvalidations(std::vector<Invalidation>* out) const;
 
   // Call Acknowledge() on all contained Invalidations.
   void AcknowledgeAll() const;
@@ -71,6 +71,6 @@
   std::map<Topic, SingleObjectInvalidationSet> map_;
 };
 
-}  // namespace syncer
+}  // namespace invalidation
 
 #endif  // COMPONENTS_INVALIDATION_PUBLIC_TOPIC_INVALIDATION_MAP_H_
diff --git a/components/no_state_prefetch/renderer/no_state_prefetch_client.cc b/components/no_state_prefetch/renderer/no_state_prefetch_client.cc
index e3913e6..2946fa5 100644
--- a/components/no_state_prefetch/renderer/no_state_prefetch_client.cc
+++ b/components/no_state_prefetch/renderer/no_state_prefetch_client.cc
@@ -22,9 +22,7 @@
 NoStatePrefetchClient::~NoStatePrefetchClient() = default;
 
 bool NoStatePrefetchClient::IsPrefetchOnly() {
-  return PrerenderHelper::GetPrerenderMode(
-             render_view()->GetMainRenderFrame()) ==
-         prerender::mojom::PrerenderMode::kPrefetchOnly;
+  return PrerenderHelper::IsPrerendering(render_view()->GetMainRenderFrame());
 }
 
 void NoStatePrefetchClient::OnDestruct() {
diff --git a/components/no_state_prefetch/renderer/prerender_helper.cc b/components/no_state_prefetch/renderer/prerender_helper.cc
index 09330e1..dc32c50 100644
--- a/components/no_state_prefetch/renderer/prerender_helper.cc
+++ b/components/no_state_prefetch/renderer/prerender_helper.cc
@@ -51,17 +51,7 @@
 
 // static.
 bool PrerenderHelper::IsPrerendering(const content::RenderFrame* render_frame) {
-  return PrerenderHelper::GetPrerenderMode(render_frame) !=
-         mojom::PrerenderMode::kNoPrerender;
-}
-
-// static.
-mojom::PrerenderMode PrerenderHelper::GetPrerenderMode(
-    const content::RenderFrame* render_frame) {
-  PrerenderHelper* helper = PrerenderHelper::Get(render_frame);
-  if (!helper)
-    return mojom::PrerenderMode::kNoPrerender;
-  return mojom::PrerenderMode::kPrefetchOnly;
+  return PrerenderHelper::Get(render_frame) != nullptr;
 }
 
 void PrerenderHelper::DidFinishDocumentLoad() {
diff --git a/components/no_state_prefetch/renderer/prerender_helper.h b/components/no_state_prefetch/renderer/prerender_helper.h
index e8e138f..d3e9283 100644
--- a/components/no_state_prefetch/renderer/prerender_helper.h
+++ b/components/no_state_prefetch/renderer/prerender_helper.h
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "components/no_state_prefetch/common/prerender_types.mojom.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "content/public/renderer/render_frame_observer_tracker.h"
 
@@ -39,9 +38,6 @@
   // Returns true if |render_frame| is currently prerendering.
   static bool IsPrerendering(const content::RenderFrame* render_frame);
 
-  static mojom::PrerenderMode GetPrerenderMode(
-      const content::RenderFrame* render_frame);
-
   std::string histogram_prefix() const { return histogram_prefix_; }
 
  private:
diff --git a/components/omnibox/browser/autocomplete_input.cc b/components/omnibox/browser/autocomplete_input.cc
index 13a4872..1a3902c 100644
--- a/components/omnibox/browser/autocomplete_input.cc
+++ b/components/omnibox/browser/autocomplete_input.cc
@@ -154,8 +154,9 @@
       type_ == metrics::OmniboxInputType::URL &&
       scheme_ == base::ASCIIToUTF16(url::kHttpScheme) &&
       !base::StartsWith(text_, scheme_, base::CompareCase::INSENSITIVE_ASCII) &&
-      !url::HostIsIPAddress(base::UTF16ToUTF8(text)) &&
-      !net::IsHostnameNonUnique(base::UTF16ToUTF8(text))) {
+      !url::HostIsIPAddress(canonicalized_url.host()) &&
+      !net::IsHostnameNonUnique(base::UTF16ToUTF8(text)) &&
+      canonicalized_url.port().empty()) {
     // Use HTTPS as the default scheme for URLs that are typed without a scheme.
     // Inputs of type UNKNOWN can still be valid URLs, but these will be mainly
     // intranet hosts which we don't to upgrade to HTTPS so we only check the
@@ -164,7 +165,11 @@
     // - Non-unique hostnames such as intranet hosts
     // - Single word hostnames (these are most likely non-unique).
     // - IP addresses
-    // TODO(crbug.com/1141691): Add tests for these cases.
+    // - URLs with a specified port. If it's a non-standard HTTP port, we can't
+    //   simply change the scheme to HTTPS and assume that these will load over
+    //   HTTPS. URLs with HTTP port 80 get their port dropped so they will be
+    //   upgraded (e.g. example.com:80 will load https://example.com).
+    DCHECK_EQ(url::kHttpScheme, canonicalized_url.scheme());
     added_default_scheme_to_typed_url_ = true;
     scheme_ = base::ASCIIToUTF16(url::kHttpsScheme);
     GURL::Replacements replacements;
diff --git a/components/omnibox/browser/autocomplete_input_unittest.cc b/components/omnibox/browser/autocomplete_input_unittest.cc
index 46a9bf33..b9639ec 100644
--- a/components/omnibox/browser/autocomplete_input_unittest.cc
+++ b/components/omnibox/browser/autocomplete_input_unittest.cc
@@ -382,15 +382,31 @@
     bool expected_added_default_scheme_to_typed_url;
   } input_cases[]{
       {ASCIIToUTF16("example.com"), GURL("https://example.com"), true},
+      // If the hostname has a port specified, the URL shouldn't be upgraded
+      // to HTTPS because we can't assume that the HTTPS site is served over the
+      // default SSL port. Port 80 is dropped in URLs so it's still upgraded.
+      {ASCIIToUTF16("example.com:80"), GURL("https://example.com"), true},
+      {ASCIIToUTF16("example.com:8080"), GURL("http://example.com:8080"),
+       false},
       // Non-URL inputs shouldn't be upgraded.
       {ASCIIToUTF16("example query"), GURL(), false},
       // IP addresses shouldn't be upgraded.
       {ASCIIToUTF16("127.0.0.1"), GURL("http://127.0.0.1"), false},
+      {ASCIIToUTF16("127.0.0.1:80"), GURL("http://127.0.0.1:80"), false},
+      {ASCIIToUTF16("127.0.0.1:8080"), GURL("http://127.0.0.1:8080"), false},
       // Non-unique hostnames shouldn't be upgraded.
       {ASCIIToUTF16("site.test"), GURL("http://site.test"), false},
       // Fully typed URLs shouldn't be upgraded.
       {ASCIIToUTF16("http://example.com"), GURL("http://example.com"), false},
       {ASCIIToUTF16("HTTP://EXAMPLE.COM"), GURL("http://example.com"), false},
+      {ASCIIToUTF16("http://example.com:80"), GURL("http://example.com"),
+       false},
+      {ASCIIToUTF16("HTTP://EXAMPLE.COM:80"), GURL("http://example.com"),
+       false},
+      {ASCIIToUTF16("http://example.com:8080"), GURL("http://example.com:8080"),
+       false},
+      {ASCIIToUTF16("HTTP://EXAMPLE.COM:8080"), GURL("http://example.com:8080"),
+       false},
   };
   for (const test_data& input_case : input_cases) {
     AutocompleteInput input(input_case.input, base::string16::npos,
diff --git a/components/optimization_guide/DEPS b/components/optimization_guide/DEPS
index a4bfbd0f..cc5a4abc 100644
--- a/components/optimization_guide/DEPS
+++ b/components/optimization_guide/DEPS
@@ -1,6 +1,10 @@
 include_rules = [
+  "+components/data_reduction_proxy/core/browser",
+  "+components/data_reduction_proxy/core/common",
   "+components/leveldb_proto",
   "+components/prefs",
+  "+components/sync_preferences",
+  "+components/unified_consent",
   "+components/variations",
   "+google_apis",
   "+net",
diff --git a/components/optimization_guide/core/BUILD.gn b/components/optimization_guide/core/BUILD.gn
index 1f274dce..6103965 100644
--- a/components/optimization_guide/core/BUILD.gn
+++ b/components/optimization_guide/core/BUILD.gn
@@ -34,6 +34,8 @@
     "optimization_guide_enums.h",
     "optimization_guide_features.cc",
     "optimization_guide_features.h",
+    "optimization_guide_permissions_util.cc",
+    "optimization_guide_permissions_util.h",
     "optimization_guide_prefs.cc",
     "optimization_guide_prefs.h",
     "optimization_guide_session_statistic.cc",
@@ -67,9 +69,11 @@
 
   deps = [
     "//base",
+    "//components/data_reduction_proxy/core/browser",
     "//components/leveldb_proto",
     "//components/optimization_guide/proto:optimization_guide_proto",
     "//components/prefs",
+    "//components/unified_consent",
     "//components/variations",
     "//components/variations/net",
     "//google_apis",
@@ -111,6 +115,7 @@
     "hints_processing_util_unittest.cc",
     "optimization_filter_unittest.cc",
     "optimization_guide_features_unittest.cc",
+    "optimization_guide_permissions_util_unittest.cc",
     "optimization_guide_session_statistic_unittest.cc",
     "optimization_guide_store_unittest.cc",
     "optimization_guide_switches_unittest.cc",
@@ -127,9 +132,13 @@
     ":test_support",
     "//base",
     "//base/test:test_support",
+    "//components/data_reduction_proxy/core/browser",
+    "//components/data_reduction_proxy/core/common",
     "//components/leveldb_proto:test_support",
     "//components/optimization_guide/proto:optimization_guide_proto",
     "//components/prefs:test_support",
+    "//components/sync_preferences:test_support",
+    "//components/unified_consent",
     "//net:test_support",
     "//services/network:network_service",
     "//services/network:test_support",
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc
index 2ef8ce66..ff45c79 100644
--- a/components/optimization_guide/core/optimization_guide_features.cc
+++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -50,6 +50,12 @@
     "OptimizationHintsFetchingAnonymousDataConsent",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables performance info in the context menu and fetching from a remote
+// Optimization Guide Service.
+const base::Feature kContextMenuPerformanceInfoAndRemoteHintFetching{
+    "ContextMenuPerformanceInfoAndRemoteHintFetching",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables the prediction of optimization targets.
 const base::Feature kOptimizationTargetPrediction{
     "OptimizationTargetPrediction", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -179,6 +185,11 @@
       kRemoteOptimizationGuideFetchingAnonymousDataConsent);
 }
 
+bool IsRemoteFetchingExplicitlyAllowedForPerformanceInfo() {
+  return base::FeatureList::IsEnabled(
+      kContextMenuPerformanceInfoAndRemoteHintFetching);
+}
+
 int MaxServerBloomFilterByteSize() {
   return base::GetFieldTrialParamByFeatureAsInt(
       kOptimizationHints, "max_bloom_filter_byte_size", 250 * 1024 /* 250KB */);
diff --git a/components/optimization_guide/core/optimization_guide_features.h b/components/optimization_guide/core/optimization_guide_features.h
index 0f232ee..54d3fff0 100644
--- a/components/optimization_guide/core/optimization_guide_features.h
+++ b/components/optimization_guide/core/optimization_guide_features.h
@@ -23,6 +23,7 @@
 extern const base::Feature kOptimizationHintsFieldTrials;
 extern const base::Feature kRemoteOptimizationGuideFetching;
 extern const base::Feature kRemoteOptimizationGuideFetchingAnonymousDataConsent;
+extern const base::Feature kContextMenuPerformanceInfoAndRemoteHintFetching;
 extern const base::Feature kOptimizationTargetPrediction;
 extern const base::Feature kOptimizationGuideModelDownloading;
 
@@ -83,6 +84,10 @@
 // anonymous data collection is enabled but are not Data Saver users.
 bool IsRemoteFetchingForAnonymousDataConsentEnabled();
 
+// Returns true if a feature that explicitly allows remote fetching has been
+// enabled.
+bool IsRemoteFetchingExplicitlyAllowedForPerformanceInfo();
+
 // The maximum data byte size for a server-provided bloom filter. This is
 // a client-side safety limit for RAM use in case server sends too large of
 // a bloom filter.
diff --git a/components/optimization_guide/core/optimization_guide_permissions_util.cc b/components/optimization_guide/core/optimization_guide_permissions_util.cc
new file mode 100644
index 0000000..d7a71e2
--- /dev/null
+++ b/components/optimization_guide/core/optimization_guide_permissions_util.cc
@@ -0,0 +1,66 @@
+// Copyright 2019 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/optimization_guide/core/optimization_guide_permissions_util.h"
+
+#include <memory>
+
+#include "base/feature_list.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
+#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_switches.h"
+#include "components/unified_consent/url_keyed_data_collection_consent_helper.h"
+
+namespace {
+
+bool IsUserDataSaverEnabledAndAllowedToFetchFromRemoteService(
+    bool is_off_the_record,
+    PrefService* pref_service) {
+  // Check if they are a data saver user.
+  return data_reduction_proxy::DataReductionProxySettings::
+      IsDataSaverEnabledByUser(is_off_the_record, pref_service);
+}
+
+bool IsUserConsentedToAnonymousDataCollectionAndAllowedToFetchFromRemoteService(
+    PrefService* pref_service) {
+  if (!optimization_guide::features::
+          IsRemoteFetchingForAnonymousDataConsentEnabled()) {
+    return false;
+  }
+
+  std::unique_ptr<unified_consent::UrlKeyedDataCollectionConsentHelper> helper =
+      unified_consent::UrlKeyedDataCollectionConsentHelper::
+          NewAnonymizedDataCollectionConsentHelper(pref_service);
+  return helper->IsEnabled();
+}
+
+}  // namespace
+
+namespace optimization_guide {
+
+bool IsUserPermittedToFetchFromRemoteOptimizationGuide(
+    bool is_off_the_record,
+    PrefService* pref_service) {
+  if (is_off_the_record)
+    return false;
+
+  if (switches::ShouldOverrideCheckingUserPermissionsToFetchHintsForTesting()) {
+    return true;
+  }
+
+  if (!features::IsRemoteFetchingEnabled())
+    return false;
+
+  if (features::IsRemoteFetchingExplicitlyAllowedForPerformanceInfo())
+    return true;
+
+  if (IsUserDataSaverEnabledAndAllowedToFetchFromRemoteService(
+          is_off_the_record, pref_service))
+    return true;
+
+  return IsUserConsentedToAnonymousDataCollectionAndAllowedToFetchFromRemoteService(
+      pref_service);
+}
+
+}  // namespace optimization_guide
diff --git a/components/optimization_guide/core/optimization_guide_permissions_util.h b/components/optimization_guide/core/optimization_guide_permissions_util.h
new file mode 100644
index 0000000..9b80ab9
--- /dev/null
+++ b/components/optimization_guide/core/optimization_guide_permissions_util.h
@@ -0,0 +1,20 @@
+// Copyright 2019 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_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_PERMISSIONS_UTIL_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_PERMISSIONS_UTIL_H_
+
+class PrefService;
+
+namespace optimization_guide {
+
+// Returns true if the user, as represented by |profile| is permitted to make
+// calls to the remote Optimization Guide Service.
+bool IsUserPermittedToFetchFromRemoteOptimizationGuide(
+    bool is_off_the_record,
+    PrefService* pref_service);
+
+}  // namespace optimization_guide
+
+#endif  // COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_PERMISSIONS_UTIL_H_
diff --git a/components/optimization_guide/core/optimization_guide_permissions_util_unittest.cc b/components/optimization_guide/core/optimization_guide_permissions_util_unittest.cc
new file mode 100644
index 0000000..9e879748e
--- /dev/null
+++ b/components/optimization_guide/core/optimization_guide_permissions_util_unittest.cc
@@ -0,0 +1,160 @@
+// Copyright 2019 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/optimization_guide/core/optimization_guide_permissions_util.h"
+
+#include "base/command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/unified_consent/pref_names.h"
+#include "components/unified_consent/unified_consent_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace optimization_guide {
+
+class OptimizationGuidePermissionsUtilTest : public testing::Test {
+ public:
+  void SetUp() override {
+    unified_consent::UnifiedConsentService::RegisterPrefs(
+        pref_service_.registry());
+    pref_service_.registry()->RegisterBooleanPref(
+        data_reduction_proxy::prefs::kDataSaverEnabled, false);
+  }
+
+  void SetDataSaverEnabled(bool enabled) {
+    data_reduction_proxy::DataReductionProxySettings::
+        SetDataSaverEnabledForTesting(&pref_service_, enabled);
+  }
+
+  void SetUrlKeyedAnonymizedDataCollectionEnabled(bool enabled) {
+    pref_service_.SetBoolean(
+        unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
+        enabled);
+  }
+
+  PrefService* pref_service() { return &pref_service_; }
+
+ private:
+  base::test::TaskEnvironment task_environment_;
+  sync_preferences::TestingPrefServiceSyncable pref_service_;
+};
+
+TEST_F(OptimizationGuidePermissionsUtilTest,
+       IsUserPermittedToFetchHintsNonDataSaverUser) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      {optimization_guide::features::kRemoteOptimizationGuideFetching});
+  SetDataSaverEnabled(false);
+
+  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
+      /*is_off_the_record=*/false, pref_service()));
+}
+
+TEST_F(OptimizationGuidePermissionsUtilTest,
+       IsUserPermittedToFetchHintsDataSaverUser) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      {optimization_guide::features::kRemoteOptimizationGuideFetching});
+  SetDataSaverEnabled(true);
+
+  EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
+      /*is_off_the_record=*/false, pref_service()));
+}
+
+TEST_F(
+    OptimizationGuidePermissionsUtilTest,
+    IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionEnabledFeatureEnabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {optimization_guide::features::kRemoteOptimizationGuideFetching,
+       optimization_guide::features::
+           kRemoteOptimizationGuideFetchingAnonymousDataConsent},
+      {});
+  SetDataSaverEnabled(false);
+  SetUrlKeyedAnonymizedDataCollectionEnabled(true);
+
+  EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
+      /*is_off_the_record=*/false, pref_service()));
+}
+
+TEST_F(
+    OptimizationGuidePermissionsUtilTest,
+    IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionDisabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {optimization_guide::features::kRemoteOptimizationGuideFetching,
+       optimization_guide::features::
+           kRemoteOptimizationGuideFetchingAnonymousDataConsent},
+      {});
+  SetDataSaverEnabled(false);
+  SetUrlKeyedAnonymizedDataCollectionEnabled(false);
+
+  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
+      /*is_off_the_record=*/false, pref_service()));
+}
+
+TEST_F(
+    OptimizationGuidePermissionsUtilTest,
+    IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionEnabledFeatureNotEnabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {optimization_guide::features::kRemoteOptimizationGuideFetching},
+      {optimization_guide::features::
+           kRemoteOptimizationGuideFetchingAnonymousDataConsent});
+  SetDataSaverEnabled(false);
+  SetUrlKeyedAnonymizedDataCollectionEnabled(true);
+
+  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
+      /*is_off_the_record=*/false, pref_service()));
+}
+
+TEST_F(OptimizationGuidePermissionsUtilTest,
+       IsUserPermittedToFetchHintsAllConsentsEnabledButHintsFetchingDisabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {}, {optimization_guide::features::kRemoteOptimizationGuideFetching});
+  SetDataSaverEnabled(true);
+  SetUrlKeyedAnonymizedDataCollectionEnabled(true);
+
+  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
+      /*is_off_the_record=*/false, pref_service()));
+}
+
+TEST_F(OptimizationGuidePermissionsUtilTest,
+       IsUserPermittedToFetchHintsPerformanceInfoFlagExplicitlyAllows) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {optimization_guide::features::kRemoteOptimizationGuideFetching,
+       optimization_guide::features::
+           kContextMenuPerformanceInfoAndRemoteHintFetching},
+      {});
+  SetDataSaverEnabled(false);
+  SetUrlKeyedAnonymizedDataCollectionEnabled(false);
+
+  EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
+      /*is_off_the_record=*/false, pref_service()));
+}
+
+TEST_F(OptimizationGuidePermissionsUtilTest,
+       IsUserPermittedToFetchHintsAllConsentsEnabledIncognitoProfile) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {optimization_guide::features::kRemoteOptimizationGuideFetching,
+       optimization_guide::features::
+           kRemoteOptimizationGuideFetchingAnonymousDataConsent,
+       optimization_guide::features::
+           kContextMenuPerformanceInfoAndRemoteHintFetching},
+      {});
+  SetDataSaverEnabled(true);
+  SetUrlKeyedAnonymizedDataCollectionEnabled(true);
+
+  EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
+      /*is_off_the_record=*/true, pref_service()));
+}
+
+}  // namespace optimization_guide
diff --git a/components/password_manager/core/browser/insecure_credentials_table.cc b/components/password_manager/core/browser/insecure_credentials_table.cc
index 04c6481..ae2dcf3 100644
--- a/components/password_manager/core/browser/insecure_credentials_table.cc
+++ b/components/password_manager/core/browser/insecure_credentials_table.cc
@@ -19,16 +19,19 @@
     sql::Statement* s) {
   std::vector<CompromisedCredentials> results;
   while (s->Step()) {
-    std::string signon_realm = s->ColumnString(0);
-    base::string16 username = s->ColumnString16(1);
+    int parent_key = s->ColumnInt64(0);
+    std::string signon_realm = s->ColumnString(1);
+    base::string16 username = s->ColumnString16(2);
     CompromiseType insecurity_type =
-        static_cast<CompromiseType>(s->ColumnInt64(2));
+        static_cast<CompromiseType>(s->ColumnInt64(3));
     base::Time create_time = base::Time::FromDeltaSinceWindowsEpoch(
-        (base::TimeDelta::FromMicroseconds(s->ColumnInt64(3))));
-    bool is_muted = !!s->ColumnInt64(4);
-
-    results.emplace_back(std::move(signon_realm), std::move(username),
-                         create_time, insecurity_type, IsMuted(is_muted));
+        (base::TimeDelta::FromMicroseconds(s->ColumnInt64(4))));
+    bool is_muted = !!s->ColumnInt64(5);
+    CompromisedCredentials issue(std::move(signon_realm), std::move(username),
+                                 create_time, insecurity_type,
+                                 IsMuted(is_muted));
+    issue.parent_key = FormPrimaryKey(parent_key);
+    results.emplace_back(std::move(issue));
   }
   return results;
 }
@@ -163,7 +166,7 @@
 
   sql::Statement s(db_->GetCachedStatement(
       SQL_FROM_HERE,
-      base::StringPrintf("SELECT signon_realm, username_value, "
+      base::StringPrintf("SELECT parent_id, signon_realm, username_value, "
                          "insecurity_type, create_time, is_muted FROM %s "
                          "INNER JOIN logins ON parent_id = logins.id "
                          "WHERE signon_realm = ? ",
@@ -173,6 +176,23 @@
   return StatementToCompromisedCredentials(&s);
 }
 
+std::vector<CompromisedCredentials> InsecureCredentialsTable::GetRows(
+    FormPrimaryKey parent_key) const {
+  DCHECK(db_);
+  DCHECK(db_->DoesTableExist(kTableName));
+
+  sql::Statement s(db_->GetCachedStatement(
+      SQL_FROM_HERE,
+      base::StringPrintf("SELECT parent_id, signon_realm, username_value, "
+                         "insecurity_type, create_time, is_muted FROM %s "
+                         "INNER JOIN logins ON parent_id = logins.id "
+                         "WHERE parent_id = ? ",
+                         kTableName)
+          .c_str()));
+  s.BindInt(0, *parent_key);
+  return StatementToCompromisedCredentials(&s);
+}
+
 bool InsecureCredentialsTable::RemoveRowsByUrlAndTime(
     const base::RepeatingCallback<bool(const GURL&)>& url_filter,
     base::Time remove_begin,
@@ -241,7 +261,7 @@
 
   sql::Statement s(db_->GetCachedStatement(
       SQL_FROM_HERE,
-      base::StringPrintf("SELECT signon_realm, username_value, "
+      base::StringPrintf("SELECT parent_id, signon_realm, username_value, "
                          "insecurity_type, create_time, is_muted FROM %s "
                          "INNER JOIN logins ON parent_id = logins.id",
                          kTableName)
diff --git a/components/password_manager/core/browser/insecure_credentials_table.h b/components/password_manager/core/browser/insecure_credentials_table.h
index 99cd489c..5586043 100644
--- a/components/password_manager/core/browser/insecure_credentials_table.h
+++ b/components/password_manager/core/browser/insecure_credentials_table.h
@@ -10,6 +10,7 @@
 #include "base/time/time.h"
 #include "base/types/strong_alias.h"
 #include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_store_sync.h"
 #include "url/gurl.h"
 
 namespace sql {
@@ -59,6 +60,8 @@
   CompromisedCredentials& operator=(CompromisedCredentials&& rhs);
   ~CompromisedCredentials();
 
+  // The primary key of an affected Login.
+  FormPrimaryKey parent_key{-1};
   // The signon_realm of the website where the credentials were compromised.
   std::string signon_realm;
   // The value of the compromised username.
@@ -103,6 +106,9 @@
   std::vector<CompromisedCredentials> GetRows(
       const std::string& signon_realm) const;
 
+  // Gets all the rows in the database for |parent_key|.
+  std::vector<CompromisedCredentials> GetRows(FormPrimaryKey parent_key) const;
+
   // Removes all compromised credentials created between |remove_begin|
   // inclusive and |remove_end| exclusive. If |url_filter| is not null, only
   // compromised credentials for matching signon_realms are removed. Returns
diff --git a/components/password_manager/core/browser/insecure_credentials_table_unittest.cc b/components/password_manager/core/browser/insecure_credentials_table_unittest.cc
index 332a580..7496653 100644
--- a/components/password_manager/core/browser/insecure_credentials_table_unittest.cc
+++ b/components/password_manager/core/browser/insecure_credentials_table_unittest.cc
@@ -35,6 +35,7 @@
 using testing::ElementsAre;
 using testing::IsEmpty;
 using testing::SizeIs;
+using testing::UnorderedElementsAre;
 
 PasswordForm TestForm() {
   PasswordForm form;
@@ -64,6 +65,15 @@
     ASSERT_TRUE(login_db_->Init());
   }
 
+  std::vector<int> GetParentIds(
+      base::span<const CompromisedCredentials> credentials) {
+    std::vector<int> ids;
+    ids.reserve(credentials.size());
+    for (const auto& credential : credentials)
+      ids.push_back(credential.parent_key.value());
+    return ids;
+  }
+
   CompromisedCredentials& test_data() { return test_data_; }
   PasswordForm& test_form() { return test_form_; }
   InsecureCredentialsTable* db() {
@@ -117,6 +127,7 @@
               ElementsAre(compromised_credentials1, compromised_credentials2));
   EXPECT_THAT(db()->GetRows(test_data().signon_realm),
               ElementsAre(compromised_credentials1, compromised_credentials2));
+  EXPECT_THAT(GetParentIds(db()->GetAllRows()), ElementsAre(1, 2));
 }
 
 TEST_F(InsecureCredentialsTableTest, SameUsernameDifferentSignonRealm) {
@@ -134,6 +145,7 @@
               ElementsAre(compromised_credentials1, compromised_credentials2));
   EXPECT_THAT(db()->GetRows(test_data().signon_realm),
               ElementsAre(compromised_credentials1));
+  EXPECT_THAT(GetParentIds(db()->GetAllRows()), ElementsAre(1, 2));
 }
 
 TEST_F(InsecureCredentialsTableTest, SameSignonRealmAndUsernameDifferentTime) {
@@ -146,6 +158,7 @@
   // It should return false because of unique constraints.
   EXPECT_FALSE(db()->AddRow(compromised_credentials2));
   EXPECT_THAT(db()->GetAllRows(), ElementsAre(compromised_credentials1));
+  EXPECT_THAT(GetParentIds(db()->GetAllRows()), ElementsAre(1));
 }
 
 TEST_F(InsecureCredentialsTableTest,
@@ -166,6 +179,7 @@
   EXPECT_THAT(db()->GetRows(test_data().signon_realm),
               ElementsAre(compromised_credentials1, compromised_credentials2,
                           compromised_credentials3));
+  EXPECT_THAT(GetParentIds(db()->GetAllRows()), ElementsAre(1, 1, 1));
 }
 
 TEST_F(InsecureCredentialsTableTest, RemoveRow) {
@@ -173,6 +187,7 @@
   EXPECT_TRUE(db()->AddRow(test_data()));
   EXPECT_THAT(db()->GetRows(test_data().signon_realm),
               ElementsAre(test_data()));
+  EXPECT_THAT(GetParentIds(db()->GetAllRows()), ElementsAre(1));
 
   EXPECT_TRUE(db()->RemoveRow(test_data().signon_realm, test_data().username,
                               RemoveCompromisedCredentialsReason::kUpdate));
@@ -203,6 +218,7 @@
   EXPECT_THAT(db()->GetAllRows(),
               ElementsAre(compromised_credentials1, compromised_credentials2,
                           compromised_credentials3));
+  EXPECT_THAT(GetParentIds(db()->GetAllRows()), ElementsAre(1, 2, 3));
 
   EXPECT_TRUE(db()->RemoveRowsByUrlAndTime(base::NullCallback(),
                                            base::Time::FromTimeT(15),
@@ -353,5 +369,32 @@
       "PasswordManager.CompromisedCredentials.CountLeakedAfterBulkCheck", 2, 1);
 }
 
+TEST_F(InsecureCredentialsTableTest, GetAllRowsWithId) {
+  EXPECT_THAT(login_db()->AddLogin(test_form()), SizeIs(1));
+  CompromisedCredentials compromised_credentials1 = test_data();
+  CompromisedCredentials compromised_credentials2 = test_data();
+  compromised_credentials2.compromise_type = CompromiseType::kReused;
+
+  EXPECT_TRUE(db()->AddRow(compromised_credentials1));
+  EXPECT_TRUE(db()->AddRow(compromised_credentials2));
+
+  EXPECT_THAT(
+      db()->GetRows(FormPrimaryKey(1)),
+      UnorderedElementsAre(compromised_credentials1, compromised_credentials2));
+  EXPECT_THAT(GetParentIds(db()->GetAllRows()), ElementsAre(1, 1));
+
+  test_form().username_value = base::ASCIIToUTF16(kUsername2);
+  test_data().username = test_form().username_value;
+
+  EXPECT_THAT(login_db()->AddLogin(test_form()), SizeIs(1));
+  EXPECT_THAT(db()->GetRows(FormPrimaryKey(2)), IsEmpty());
+
+  compromised_credentials1 = test_data();
+  EXPECT_TRUE(db()->AddRow(compromised_credentials1));
+  EXPECT_THAT(db()->GetRows(FormPrimaryKey(2)),
+              UnorderedElementsAre(compromised_credentials1));
+  EXPECT_THAT(GetParentIds(db()->GetAllRows()), ElementsAre(1, 1, 2));
+}
+
 }  // namespace
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index 75f628b..dc76a4a 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -1665,6 +1665,12 @@
   return StatementToForms(&s, nullptr, key_to_form_map);
 }
 
+std::vector<CompromisedCredentials> LoginDatabase::GetCompromisedCredentials(
+    FormPrimaryKey parent_key) {
+  TRACE_EVENT0("passwords", "LoginDatabase::GetCompromisedCredentials");
+  return insecure_credentials_table_.GetRows(parent_key);
+}
+
 bool LoginDatabase::GetAutofillableLogins(
     std::vector<std::unique_ptr<PasswordForm>>* forms) {
   TRACE_EVENT0("passwords", "LoginDatabase::GetAutofillableLogins");
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h
index d209bb3..96636f1 100644
--- a/components/password_manager/core/browser/login_database.h
+++ b/components/password_manager/core/browser/login_database.h
@@ -148,6 +148,11 @@
   FormRetrievalResult GetAllLogins(PrimaryKeyToFormMap* key_to_form_map)
       WARN_UNUSED_RESULT;
 
+  // Gets the complete list of all compromised credentials for the password form
+  // with primary key `parent_key`.
+  std::vector<CompromisedCredentials> GetCompromisedCredentials(
+      FormPrimaryKey parent_key) WARN_UNUSED_RESULT;
+
   // Gets the complete list of not blocklisted credentials.
   bool GetAutofillableLogins(std::vector<std::unique_ptr<PasswordForm>>* forms)
       WARN_UNUSED_RESULT;
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h
index e389f0f..c27a975 100644
--- a/components/password_manager/core/browser/mock_password_store.h
+++ b/components/password_manager/core/browser/mock_password_store.h
@@ -121,6 +121,8 @@
   MOCK_METHOD0(RollbackTransaction, void());
   MOCK_METHOD0(CommitTransaction, bool());
   MOCK_METHOD1(ReadAllLogins, FormRetrievalResult(PrimaryKeyToFormMap*));
+  MOCK_METHOD1(ReadSecurityIssues,
+               std::vector<CompromisedCredentials>(FormPrimaryKey));
   MOCK_METHOD1(RemoveLoginByPrimaryKeySync, PasswordStoreChangeList(int));
   MOCK_METHOD0(GetMetadataStore, PasswordStoreSync::MetadataStore*());
   MOCK_CONST_METHOD0(IsAccountStore, bool());
diff --git a/components/password_manager/core/browser/password_store_impl.cc b/components/password_manager/core/browser/password_store_impl.cc
index 21fc8042..71c96b24 100644
--- a/components/password_manager/core/browser/password_store_impl.cc
+++ b/components/password_manager/core/browser/password_store_impl.cc
@@ -323,6 +323,13 @@
   return login_db_->GetAllLogins(key_to_form_map);
 }
 
+std::vector<CompromisedCredentials> PasswordStoreImpl::ReadSecurityIssues(
+    FormPrimaryKey parent_key) {
+  if (!login_db_)
+    return {};
+  return login_db_->GetCompromisedCredentials(parent_key);
+}
+
 PasswordStoreChangeList PasswordStoreImpl::RemoveLoginByPrimaryKeySync(
     int primary_key) {
   DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
diff --git a/components/password_manager/core/browser/password_store_impl.h b/components/password_manager/core/browser/password_store_impl.h
index 7afdc48..edb9eee 100644
--- a/components/password_manager/core/browser/password_store_impl.h
+++ b/components/password_manager/core/browser/password_store_impl.h
@@ -99,6 +99,8 @@
   bool CommitTransaction() override;
   FormRetrievalResult ReadAllLogins(
       PrimaryKeyToFormMap* key_to_form_map) override;
+  std::vector<CompromisedCredentials> ReadSecurityIssues(
+      FormPrimaryKey parent_key) override;
   PasswordStoreChangeList RemoveLoginByPrimaryKeySync(int primary_key) override;
   PasswordStoreSync::MetadataStore* GetMetadataStore() override;
   bool IsAccountStore() const override;
diff --git a/components/password_manager/core/browser/password_store_sync.h b/components/password_manager/core/browser/password_store_sync.h
index d06da7d0..1546668 100644
--- a/components/password_manager/core/browser/password_store_sync.h
+++ b/components/password_manager/core/browser/password_store_sync.h
@@ -23,6 +23,7 @@
 struct CompromisedCredentials;
 struct PasswordForm;
 
+using FormPrimaryKey = base::StrongAlias<class FormPrimaryKeyTag, int>;
 using PrimaryKeyToFormMap = std::map<int, std::unique_ptr<PasswordForm>>;
 
 // This enum is used to determine result status when deleting undecryptable
@@ -123,6 +124,10 @@
   virtual FormRetrievalResult ReadAllLogins(
       PrimaryKeyToFormMap* key_to_form_map) WARN_UNUSED_RESULT = 0;
 
+  // Returns compromised credentials for the provided |parent_key|.
+  virtual std::vector<CompromisedCredentials> ReadSecurityIssues(
+      FormPrimaryKey parent_key) = 0;
+
   // Deletes logins that cannot be decrypted.
   virtual DatabaseCleanupResult DeleteUndecryptableLogins() = 0;
 
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index 4fdcf023..7a8cb2d 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -271,6 +271,10 @@
               ReadAllLogins,
               (PrimaryKeyToFormMap*),
               (override));
+  MOCK_METHOD(std::vector<CompromisedCredentials>,
+              ReadSecurityIssues,
+              (FormPrimaryKey),
+              (override));
   MOCK_METHOD(PasswordStoreChangeList,
               RemoveLoginByPrimaryKeySync,
               (int),
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index afeb7769..6262f95 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -422,6 +422,12 @@
   return FormRetrievalResult::kDbError;
 }
 
+std::vector<CompromisedCredentials> TestPasswordStore::ReadSecurityIssues(
+    FormPrimaryKey parent_key) {
+  NOTIMPLEMENTED();
+  return std::vector<CompromisedCredentials>();
+}
+
 PasswordStoreChangeList TestPasswordStore::RemoveLoginByPrimaryKeySync(
     int primary_key) {
   NOTIMPLEMENTED();
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h
index ca5d485..5c3e132 100644
--- a/components/password_manager/core/browser/test_password_store.h
+++ b/components/password_manager/core/browser/test_password_store.h
@@ -141,6 +141,8 @@
   bool CommitTransaction() override;
   FormRetrievalResult ReadAllLogins(
       PrimaryKeyToFormMap* key_to_form_map) override;
+  std::vector<CompromisedCredentials> ReadSecurityIssues(
+      FormPrimaryKey parent_key) override;
   PasswordStoreChangeList RemoveLoginByPrimaryKeySync(int primary_key) override;
   PasswordStoreSync::MetadataStore* GetMetadataStore() override;
   bool IsAccountStore() const override;
diff --git a/components/pdf_strings.grdp b/components/pdf_strings.grdp
index f4f6325..637094a8 100644
--- a/components/pdf_strings.grdp
+++ b/components/pdf_strings.grdp
@@ -88,6 +88,12 @@
     <message name="IDS_PDF_PROPERTIES_FAST_WEB_VIEW" desc="Name of the property describing whether the PDF document is organized to be viewed efficiently in network environments.">
       Fast web view:
     </message>
+    <message name="IDS_PDF_PROPERTIES_FAST_WEB_VIEW_NO" desc="Label indicating that the PDF document is not organized to be viewed efficiently in network environments.">
+      No
+    </message>
+    <message name="IDS_PDF_PROPERTIES_FAST_WEB_VIEW_YES" desc="Label indicating that the PDF document is organized to be viewed efficiently in network environments.">
+      Yes
+    </message>
 
     <message name="IDS_PDF_TOOLTIP_ROTATE_CW" desc="Button tooltip for the button which rotates a PDF document clockwise">
       Rotate clockwise
diff --git a/components/pdf_strings_grdp/IDS_PDF_PROPERTIES_FAST_WEB_VIEW_NO.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_PROPERTIES_FAST_WEB_VIEW_NO.png.sha1
new file mode 100644
index 0000000..6a641d380
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_PROPERTIES_FAST_WEB_VIEW_NO.png.sha1
@@ -0,0 +1 @@
+655257b2deb63eba2b20cb7844f9e3d97e6337c1
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_PROPERTIES_FAST_WEB_VIEW_YES.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_PROPERTIES_FAST_WEB_VIEW_YES.png.sha1
new file mode 100644
index 0000000..c66e2eec5
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_PROPERTIES_FAST_WEB_VIEW_YES.png.sha1
@@ -0,0 +1 @@
+0dcdcf57e7aa53d2f27dfc832a51234aa26b6631
\ No newline at end of file
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index 3727500..b50451b 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -59,6 +59,7 @@
     "graph/graph_impl.h",
     "graph/graph_impl_operations.cc",
     "graph/graph_impl_operations.h",
+    "graph/graph_impl_util.h",
     "graph/graph_operations.cc",
     "graph/graph_registered.cc",
     "graph/node.cc",
diff --git a/components/performance_manager/graph/frame_node_impl.cc b/components/performance_manager/graph/frame_node_impl.cc
index 32b82018..78705eb 100644
--- a/components/performance_manager/graph/frame_node_impl.cc
+++ b/components/performance_manager/graph/frame_node_impl.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "components/performance_manager/graph/graph_impl.h"
+#include "components/performance_manager/graph/graph_impl_util.h"
 #include "components/performance_manager/graph/page_node_impl.h"
 #include "components/performance_manager/graph/process_node_impl.h"
 #include "components/performance_manager/graph/worker_node_impl.h"
@@ -414,11 +415,8 @@
 const base::flat_set<const FrameNode*> FrameNodeImpl::GetChildFrameNodes()
     const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::flat_set<const FrameNode*> children;
-  for (auto* child : child_frame_nodes())
-    children.insert(static_cast<const FrameNode*>(child));
-  DCHECK_EQ(children.size(), child_frame_nodes().size());
-  return children;
+
+  return UpcastNodeSet<FrameNode>(child_frame_nodes());
 }
 
 bool FrameNodeImpl::VisitOpenedPageNodes(const PageNodeVisitor& visitor) const {
@@ -434,11 +432,7 @@
 const base::flat_set<const PageNode*> FrameNodeImpl::GetOpenedPageNodes()
     const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::flat_set<const PageNode*> opened;
-  for (auto* page : opened_page_nodes())
-    opened.insert(static_cast<const PageNode*>(page));
-  DCHECK_EQ(opened.size(), opened_page_nodes().size());
-  return opened;
+  return UpcastNodeSet<PageNode>(opened_page_nodes());
 }
 
 FrameNodeImpl::LifecycleState FrameNodeImpl::GetLifecycleState() const {
@@ -484,11 +478,7 @@
 const base::flat_set<const WorkerNode*> FrameNodeImpl::GetChildWorkerNodes()
     const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::flat_set<const WorkerNode*> children;
-  for (auto* child : child_worker_nodes())
-    children.insert(static_cast<const WorkerNode*>(child));
-  DCHECK_EQ(children.size(), child_worker_nodes().size());
-  return children;
+  return UpcastNodeSet<WorkerNode>(child_worker_nodes());
 }
 
 bool FrameNodeImpl::VisitChildDedicatedWorkers(
diff --git a/components/performance_manager/graph/graph_impl_util.h b/components/performance_manager/graph/graph_impl_util.h
new file mode 100644
index 0000000..f67a8089
--- /dev/null
+++ b/components/performance_manager/graph/graph_impl_util.h
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_GRAPH_GRAPH_IMPL_UTIL_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_GRAPH_GRAPH_IMPL_UTIL_H_
+
+#include "base/containers/flat_set.h"
+
+namespace performance_manager {
+
+template <typename PublicNodeClass, typename NodeImplClass>
+base::flat_set<const PublicNodeClass*> UpcastNodeSet(
+    const base::flat_set<NodeImplClass*>& node_set) {
+  // As node_set is a flat_set, its contents are sorted and unique already.
+  return base::flat_set<const PublicNodeClass*>(
+      base::sorted_unique, node_set.begin(), node_set.end());
+}
+
+}  // namespace performance_manager
+
+#endif  // COMPONENTS_PERFORMANCE_MANAGER_GRAPH_GRAPH_IMPL_UTIL_H_
diff --git a/components/performance_manager/graph/graph_operations.cc b/components/performance_manager/graph/graph_operations.cc
index 07ec5586..3cc2982 100644
--- a/components/performance_manager/graph/graph_operations.cc
+++ b/components/performance_manager/graph/graph_operations.cc
@@ -6,42 +6,23 @@
 
 #include "components/performance_manager/graph/frame_node_impl.h"
 #include "components/performance_manager/graph/graph_impl_operations.h"
+#include "components/performance_manager/graph/graph_impl_util.h"
 #include "components/performance_manager/graph/page_node_impl.h"
 #include "components/performance_manager/graph/process_node_impl.h"
 
 namespace performance_manager {
 
-namespace {
-
-template <typename ImplContainerType, typename PublicContainerType>
-PublicContainerType ConvertContainer(const ImplContainerType& impls) {
-  PublicContainerType result;
-  for (auto* impl : impls) {
-    // Use the hinting insert, which all containers support. This will result
-    // in the same ordering for vectors, and for containers that are sorted it
-    // will actually provide the optimal hint. For hashed containers this
-    // parameter will be ignored so is effectively a nop.
-    result.insert(result.end(), impl);
-  }
-  return result;
-}
-
-}  // namespace
-
 // static
 base::flat_set<const PageNode*> GraphOperations::GetAssociatedPageNodes(
     const ProcessNode* process) {
-  return ConvertContainer<base::flat_set<PageNodeImpl*>,
-                          base::flat_set<const PageNode*>>(
-      GraphImplOperations::GetAssociatedPageNodes(
-          ProcessNodeImpl::FromNode(process)));
+  return UpcastNodeSet<PageNode>(GraphImplOperations::GetAssociatedPageNodes(
+      ProcessNodeImpl::FromNode(process)));
 }
 
 // static
 base::flat_set<const ProcessNode*> GraphOperations::GetAssociatedProcessNodes(
     const PageNode* page) {
-  return ConvertContainer<base::flat_set<ProcessNodeImpl*>,
-                          base::flat_set<const ProcessNode*>>(
+  return UpcastNodeSet<ProcessNode>(
       GraphImplOperations::GetAssociatedProcessNodes(
           PageNodeImpl::FromNode(page)));
 }
@@ -49,9 +30,8 @@
 // static
 std::vector<const FrameNode*> GraphOperations::GetFrameNodes(
     const PageNode* page) {
-  return ConvertContainer<std::vector<FrameNodeImpl*>,
-                          std::vector<const FrameNode*>>(
-      GraphImplOperations::GetFrameNodes(PageNodeImpl::FromNode(page)));
+  auto impls = GraphImplOperations::GetFrameNodes(PageNodeImpl::FromNode(page));
+  return std::vector<const FrameNode*>(impls.begin(), impls.end());
 }
 
 // static
diff --git a/components/performance_manager/graph/node.cc b/components/performance_manager/graph/node.cc
index 999000a..a15095e9 100644
--- a/components/performance_manager/graph/node.cc
+++ b/components/performance_manager/graph/node.cc
@@ -4,8 +4,6 @@
 
 #include "components/performance_manager/public/graph/node.h"
 
-#include "components/performance_manager/graph/node_base.h"
-
 namespace performance_manager {
 
 Node::Node() = default;
diff --git a/components/performance_manager/graph/process_node_impl.cc b/components/performance_manager/graph/process_node_impl.cc
index d48a4e5..5cbd26a5 100644
--- a/components/performance_manager/graph/process_node_impl.cc
+++ b/components/performance_manager/graph/process_node_impl.cc
@@ -9,6 +9,7 @@
 #include "base/check_op.h"
 #include "components/performance_manager/graph/frame_node_impl.h"
 #include "components/performance_manager/graph/graph_impl.h"
+#include "components/performance_manager/graph/graph_impl_util.h"
 #include "components/performance_manager/graph/page_node_impl.h"
 #include "components/performance_manager/graph/worker_node_impl.h"
 #include "components/performance_manager/public/execution_context/execution_context_registry.h"
@@ -241,23 +242,12 @@
 
 base::flat_set<const FrameNode*> ProcessNodeImpl::GetFrameNodes() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::flat_set<const FrameNode*> frames;
-  const base::flat_set<FrameNodeImpl*>& frame_impls = frame_nodes();
-  for (auto* frame_impl : frame_impls) {
-    const FrameNode* frame = frame_impl;
-    frames.insert(frame);
-  }
-  return frames;
+  return UpcastNodeSet<FrameNode>(frame_nodes());
 }
 
 base::flat_set<const WorkerNode*> ProcessNodeImpl::GetWorkerNodes() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::flat_set<const WorkerNode*> workers;
-  for (auto* worker_impl : worker_nodes_) {
-    const WorkerNode* worker = worker_impl;
-    workers.insert(worker);
-  }
-  return workers;
+  return UpcastNodeSet<WorkerNode>(worker_nodes_);
 }
 
 bool ProcessNodeImpl::GetMainThreadTaskLoadIsLow() const {
diff --git a/components/performance_manager/v8_memory/v8_context_tracker.cc b/components/performance_manager/v8_memory/v8_context_tracker.cc
index e89b524..df34397 100644
--- a/components/performance_manager/v8_memory/v8_context_tracker.cc
+++ b/components/performance_manager/v8_memory/v8_context_tracker.cc
@@ -200,6 +200,7 @@
     FrameNodeImpl* parent_frame_node,
     const blink::RemoteFrameToken& remote_frame_token,
     mojom::IframeAttributionDataPtr iframe_attribution_data) {
+  DCHECK(parent_frame_node);
   DCHECK_ON_GRAPH_SEQUENCE(parent_frame_node->graph());
 
   // RemoteFrameTokens are issued by the browser to a renderer, so if we receive
@@ -222,7 +223,8 @@
   };
   std::unique_ptr<Data> data(
       new Data{mojo::GetBadMessageCallback(), remote_frame_token,
-               std::move(iframe_attribution_data), nullptr});
+               std::move(iframe_attribution_data), nullptr,
+               parent_frame_node->GetWeakPtr()});
 
   auto on_pm_seq = base::BindOnce([](std::unique_ptr<Data> data, Graph* graph) {
     DCHECK(data);
@@ -477,6 +479,11 @@
   DCHECK(bad_message_callback);
   DCHECK_ON_GRAPH_SEQUENCE(frame_node->graph());
 
+  if (!frame_node->parent_frame_node()) {
+    // This may happen for custom HTML elements. Ignore such calls.
+    return;
+  }
+
   if (frame_node->parent_frame_node() != parent_frame_node) {
     std::move(bad_message_callback)
         .Run("OnRemoteIframeAttached has wrong parent frame");
diff --git a/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc b/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
index c614899..b506a664 100644
--- a/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
+++ b/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
@@ -58,6 +58,62 @@
   ExpectCounts(1, 1, 0, 0);
 }
 
+IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, SameOriginIframeAttributionData) {
+  GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_a.html"));
+  ASSERT_TRUE(NavigateToURL(shell(), urla));
+
+  // Get pointers to the RFHs for each frame.
+  auto* contents = shell()->web_contents();
+  content::RenderFrameHost* main_rfh = contents->GetMainFrame();
+  content::RenderFrameHost* child_rfh = nullptr;
+  auto frames = contents->GetAllFrames();
+  ASSERT_EQ(2u, frames.size());
+  for (auto* rfh : contents->GetAllFrames()) {
+    if (rfh != main_rfh)
+      child_rfh = rfh;
+  }
+  auto frame_node =
+      PerformanceManager::GetFrameNodeForRenderFrameHost(child_rfh);
+
+  RunInGraph([&frame_node](Graph* graph) {
+    ASSERT_TRUE(frame_node);
+    auto* v8_context_tracker = V8ContextTracker::GetFromGraph(graph);
+    ASSERT_TRUE(v8_context_tracker);
+    auto* ec_state = v8_context_tracker->GetExecutionContextState(
+        frame_node->GetFrameToken());
+    ASSERT_TRUE(ec_state);
+    ASSERT_TRUE(ec_state->iframe_attribution_data);
+  });
+}
+
+IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, CrossOriginIframeAttributionData) {
+  GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html"));
+  ASSERT_TRUE(NavigateToURL(shell(), urla));
+
+  // Get pointers to the RFHs for each frame.
+  auto* contents = shell()->web_contents();
+  content::RenderFrameHost* main_rfh = contents->GetMainFrame();
+  content::RenderFrameHost* child_rfh = nullptr;
+  auto frames = contents->GetAllFrames();
+  ASSERT_EQ(2u, frames.size());
+  for (auto* rfh : contents->GetAllFrames()) {
+    if (rfh != main_rfh)
+      child_rfh = rfh;
+  }
+  auto frame_node =
+      PerformanceManager::GetFrameNodeForRenderFrameHost(child_rfh);
+
+  RunInGraph([&frame_node](Graph* graph) {
+    ASSERT_TRUE(frame_node);
+    auto* v8_context_tracker = V8ContextTracker::GetFromGraph(graph);
+    ASSERT_TRUE(v8_context_tracker);
+    auto* ec_state = v8_context_tracker->GetExecutionContextState(
+        frame_node->GetFrameToken());
+    ASSERT_TRUE(ec_state);
+    ASSERT_TRUE(ec_state->iframe_attribution_data);
+  });
+}
+
 IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, SameDocNavigation) {
   ExpectCounts(0, 0, 0, 0);
   GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html"));
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index eefcf3c..122e9fe 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -601,13 +601,13 @@
     Screen capture paused
   </message>
   <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE" desc="The message for notification informing the user that screen capture is paused.">
-    Screen capture was paused by your administrator due to content on your screen.
+    Administrator policy disables screen sharing with <ph name="APPLICATION_TITLE">$1<ex>example.com</ex></ph> when confidential content is visible
   </message>
   <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_TITLE" desc="The title for notification informing the user that screen capture is resumed.">
     Screen capture resumed
   </message>
   <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE" desc="The message for notification informing the user that screen capture is resumed.">
-    Screen capture was resumed.
+    Screen sharing with <ph name="APPLICATION_TITLE">$1<ex>example.com</ex></ph> was resumed
   </message>
 
 </grit-part>
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE.png.sha1
index b229c3f..d39536a2 100644
--- a/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE.png.sha1
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE.png.sha1
@@ -1 +1 @@
-ebfe478eec17a1a367f7a7caae5a30ba64f83cc3
\ No newline at end of file
+1d7da8eb09728a9bf31c63625f04098d846c29f1
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE.png.sha1
index e140196..2c78cd1 100644
--- a/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE.png.sha1
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE.png.sha1
@@ -1 +1 @@
-37963de8b2789e22596fb9041eaa7be6598431a3
\ No newline at end of file
+745012bb15b10bc8cc686c57baa7917977c0accd
\ No newline at end of file
diff --git a/components/search_engines/prepopulated_engines.json b/components/search_engines/prepopulated_engines.json
index 7c1938aad..6e83c8e 100644
--- a/components/search_engines/prepopulated_engines.json
+++ b/components/search_engines/prepopulated_engines.json
@@ -28,7 +28,7 @@
     // Increment this if you change the data in ways that mean users with
     // existing data should get a new version. Otherwise, existing data may
     // continue to be used and updates made here will not always appear.
-    "kCurrentDataVersion": 124
+    "kCurrentDataVersion": 125
   },
 
   // The following engines are included in country lists and are added to the
diff --git a/components/shared_highlighting/core/common/BUILD.gn b/components/shared_highlighting/core/common/BUILD.gn
index 39e5b8a..47d73ad 100644
--- a/components/shared_highlighting/core/common/BUILD.gn
+++ b/components/shared_highlighting/core/common/BUILD.gn
@@ -4,6 +4,8 @@
 
 static_library("common") {
   sources = [
+    "disabled_sites.cc",
+    "disabled_sites.h",
     "shared_highlighting_metrics.cc",
     "shared_highlighting_metrics.h",
     "text_fragment.cc",
@@ -19,12 +21,14 @@
     "//components/search_engines:search_engine_utils",
     "//services/metrics/public/cpp:metrics_cpp",
     "//services/metrics/public/cpp:ukm_builders",
+    "//third_party/re2",
   ]
 }
 
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "disabled_sites_unittest.cc",
     "shared_highlighting_metrics_unittest.cc",
     "text_fragment_unittest.cc",
     "text_fragments_utils_unittest.cc",
diff --git a/components/shared_highlighting/core/common/DEPS b/components/shared_highlighting/core/common/DEPS
index f5a2418..22038631 100644
--- a/components/shared_highlighting/core/common/DEPS
+++ b/components/shared_highlighting/core/common/DEPS
@@ -4,5 +4,6 @@
   "+components/ukm/test_ukm_recorder.h",
   "+net/base",
   "+services/metrics/public",
+  "+third_party/re2",
   "+url",
 ]
\ No newline at end of file
diff --git a/components/shared_highlighting/core/common/disabled_sites.cc b/components/shared_highlighting/core/common/disabled_sites.cc
new file mode 100644
index 0000000..da15280
--- /dev/null
+++ b/components/shared_highlighting/core/common/disabled_sites.cc
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/shared_highlighting/core/common/disabled_sites.h"
+
+#include "third_party/re2/src/re2/re2.h"
+
+#include <map>
+#include <utility>
+
+namespace shared_highlighting {
+
+bool ShouldOfferLinkToText(const GURL& url) {
+  // If a URL's host matches a key in this map, then the path will be tested
+  // against the RE stored in the value. For example, {"foo.com", ".*"} means
+  // any page on the foo.com domain.
+  const static std::map<std::string, std::string> kBlocklist = {
+      {"youtube.com", ".*"},
+      // TODO(crbug.com/1157981): special case this to cover other Google TLDs
+      {"google.com", "^\\/amp\\/.*"}};
+
+  const std::string domain =
+      url.host().compare(0, 4, "www.") == 0 ? url.host().substr(4) : url.host();
+  auto it = kBlocklist.find(domain);
+  if (it != kBlocklist.end()) {
+    return !re2::RE2::FullMatch(url.path(), it->second);
+  }
+  return true;
+}
+
+}  // namespace shared_highlighting
diff --git a/components/shared_highlighting/core/common/disabled_sites.h b/components/shared_highlighting/core/common/disabled_sites.h
new file mode 100644
index 0000000..01d509e
--- /dev/null
+++ b/components/shared_highlighting/core/common/disabled_sites.h
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SHARED_HIGHLIGHTING_CORE_COMMON_DISABLED_SITES_H_
+#define COMPONENTS_SHARED_HIGHLIGHTING_CORE_COMMON_DISABLED_SITES_H_
+
+#include "url/gurl.h"
+
+namespace shared_highlighting {
+
+// Returns true iff Link to Text menu options should be enabled on this page.
+// Uses a blocklist to identify certain sites where personalized or dynamic
+// content make it unlikely that a generated URL will actually work when
+// shared.
+bool ShouldOfferLinkToText(const GURL& url);
+
+}  // namespace shared_highlighting
+
+#endif  // COMPONENTS_SHARED_HIGHLIGHTING_CORE_COMMON_DISABLED_SITES_H_
diff --git a/components/shared_highlighting/core/common/disabled_sites_unittest.cc b/components/shared_highlighting/core/common/disabled_sites_unittest.cc
new file mode 100644
index 0000000..ce121cc9
--- /dev/null
+++ b/components/shared_highlighting/core/common/disabled_sites_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/shared_highlighting/core/common/disabled_sites.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace shared_highlighting {
+namespace {
+
+TEST(DisabledSitesTest, AllPaths) {
+  EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://www.youtube.com")));
+  EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://www.youtube.com/somepage")));
+  EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://youtube.com")));
+  EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://youtube.com/somepage")));
+}
+
+TEST(DisabledSitesTest, SpecificPages) {
+  // Paths starting with /amp/ are disabled.
+  EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://www.google.com/amp/")));
+  EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://www.google.com/amp/foo")));
+  EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://google.com/amp/")));
+  EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://google.com/amp/foo")));
+
+  // Other paths are not.
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.google.com")));
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.google.com/somepage")));
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://google.com")));
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://google.com/somepage")));
+
+  // Paths with /amp/ later on are also not affected.
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://google.com/foo/amp/")));
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://google.com/foo/amp/bar")));
+}
+
+TEST(DisabledSitesTest, NonMatchingHost) {
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.example.com")));
+}
+
+}  // namespace
+}  // namespace shared_highlighting
diff --git a/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc b/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
index 453b0d9c..739316b6 100644
--- a/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
+++ b/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
@@ -80,10 +80,6 @@
     false,
 };
 
-// Name of the GAIA cookie that is being observed to detect when available
-// accounts have changed in the content-area.
-const char* const kGaiaCookieName = "SAPISID";
-
 // State of requests to Gaia logout endpoint. Used as entry for histogram
 // |Signin.GaiaCookieManager.Logout|.
 enum LogoutRequestState {
@@ -482,7 +478,8 @@
   // testing contexts.
   if (cookie_manager) {
     cookie_manager->AddCookieChangeListener(
-        GaiaUrls::GetInstance()->secure_google_url(), kGaiaCookieName,
+        GaiaUrls::GetInstance()->secure_google_url(),
+        GaiaConstants::kGaiaSigninCookieName,
         cookie_listener_receiver_.BindNewPipeAndPassRemote());
     cookie_listener_receiver_.set_disconnect_handler(base::BindOnce(
         &GaiaCookieManagerService::OnCookieListenerConnectionError,
@@ -602,10 +599,11 @@
   GURL google_url = GaiaUrls::GetInstance()->secure_google_url();
   std::unique_ptr<net::CanonicalCookie> cookie =
       net::CanonicalCookie::CreateSanitizedCookie(
-          google_url, kGaiaCookieName, std::string(), "." + google_url.host(),
-          "/", base::Time(), base::Time(), base::Time(), true /* secure */,
-          false /* httponly */, net::CookieSameSite::NO_RESTRICTION,
-          net::COOKIE_PRIORITY_DEFAULT, false /* same_party */);
+          google_url, GaiaConstants::kGaiaSigninCookieName, std::string(),
+          "." + google_url.host(), "/", base::Time(), base::Time(),
+          base::Time(), true /* secure */, false /* httponly */,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
+          false /* same_party */);
   OnCookieChange(
       net::CookieChangeInfo(*cookie, net::CookieAccessResult(),
                             net::CookieChangeCause::UNKNOWN_DELETION));
@@ -693,7 +691,7 @@
 
 void GaiaCookieManagerService::OnCookieChange(
     const net::CookieChangeInfo& change) {
-  DCHECK_EQ(kGaiaCookieName, change.cookie.Name());
+  DCHECK_EQ(GaiaConstants::kGaiaSigninCookieName, change.cookie.Name());
   DCHECK(change.cookie.IsDomainMatch(
       GaiaUrls::GetInstance()->google_url().host()));
   list_accounts_stale_ = true;
diff --git a/components/signin/ios/browser/account_consistency_service.h b/components/signin/ios/browser/account_consistency_service.h
index 37224721..a5ab951 100644
--- a/components/signin/ios/browser/account_consistency_service.h
+++ b/components/signin/ios/browser/account_consistency_service.h
@@ -44,9 +44,6 @@
   // Google authentication cookies are managed by |AccountReconcilor|).
   static const char kChromeConnectedCookieName[];
 
-  // Name of the Google authentication cookie.
-  static const char kGaiaCookieName[];
-
   AccountConsistencyService(
       web::BrowserState* browser_state,
       AccountReconcilor* account_reconcilor,
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index 537a327..18899b4 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -22,6 +22,7 @@
 #include "components/signin/public/base/account_consistency_method.h"
 #include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
+#include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "ios/web/common/web_view_creation_util.h"
 #include "ios/web/public/browser_state.h"
@@ -67,7 +68,8 @@
   kGaiaCookiePresentOnNavigation = 0,
   kGaiaCookieAbsentOnGoogleAssociatedDomainNavigation = 1,
   kGaiaCookieAbsentOnAddSessionNavigation = 2,
-  kMaxValue = kGaiaCookieAbsentOnAddSessionNavigation
+  kGaiaCookieRestoredOnShowInfobar = 3,
+  kMaxValue = kGaiaCookieRestoredOnShowInfobar
 };
 
 // Records the state of Gaia cookies for a navigation in UMA histogram.
@@ -329,6 +331,8 @@
   // condition in which the infobar is dismissed prior to the page load.
   if (gaia_cookies_restored_) {
     [delegate_ onRestoreGaiaCookies];
+    LogIOSGaiaCookiesState(
+        GaiaCookieStateOnSignedInNavigation::kGaiaCookieRestoredOnShowInfobar);
     gaia_cookies_restored_ = false;
   }
 
@@ -354,8 +358,6 @@
 const char AccountConsistencyService::kChromeConnectedCookieName[] =
     "CHROME_CONNECTED";
 
-const char AccountConsistencyService::kGaiaCookieName[] = "SAPISID";
-
 AccountConsistencyService::AccountConsistencyService(
     web::BrowserState* browser_state,
     AccountReconcilor* account_reconcilor,
@@ -425,7 +427,7 @@
     const net::CookieAccessResultList& cookie_list,
     const net::CookieAccessResultList& unused_excluded_cookies) {
   for (const auto& cookie : cookie_list) {
-    if (cookie.cookie.Name() == kGaiaCookieName) {
+    if (cookie.cookie.Name() == GaiaConstants::kGaiaSigninCookieName) {
       LogIOSGaiaCookiesState(
           GaiaCookieStateOnSignedInNavigation::kGaiaCookiePresentOnNavigation);
       return;
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index f13f837..211d685 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -18,7 +18,6 @@
 #include "components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h"
 #include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
 #include "components/subresource_filter/content/browser/page_load_statistics.h"
-#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
@@ -439,7 +438,7 @@
       client_->GetSafeBrowsingDatabaseManager()) {
     throttles->push_back(
         std::make_unique<SubresourceFilterSafeBrowsingActivationThrottle>(
-            navigation_handle, client_->GetProfileInteractionManager(),
+            navigation_handle, client_.get(),
             content::GetIOThreadTaskRunner({}),
             client_->GetSafeBrowsingDatabaseManager()));
   }
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
index a3e338e..2c725f2b 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
@@ -183,6 +183,12 @@
 
   // SubresourceFilterClient:
   void ShowNotification() override { ++disallowed_notification_count_; }
+  mojom::ActivationLevel OnPageActivationComputed(
+      content::NavigationHandle* navigation_handle,
+      mojom::ActivationLevel effective_activation_level,
+      ActivationDecision* decision) override {
+    return effective_activation_level;
+  }
   void OnAdsViolationTriggered(
       content::RenderFrameHost* rfh,
       mojom::AdsViolation triggered_violation) override {}
@@ -190,10 +196,6 @@
   GetSafeBrowsingDatabaseManager() override {
     return database_manager_;
   }
-  subresource_filter::ProfileInteractionManager* GetProfileInteractionManager()
-      override {
-    return nullptr;
-  }
   void OnReloadRequested() override {}
 
   void CreateSafeBrowsingDatabaseManager() {
diff --git a/components/subresource_filter/content/browser/profile_interaction_manager.h b/components/subresource_filter/content/browser/profile_interaction_manager.h
index 8081870c..015ecf4 100644
--- a/components/subresource_filter/content/browser/profile_interaction_manager.h
+++ b/components/subresource_filter/content/browser/profile_interaction_manager.h
@@ -5,7 +5,6 @@
 #ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_PROFILE_INTERACTION_MANAGER_H_
 #define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_PROFILE_INTERACTION_MANAGER_H_
 
-#include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
 #include "components/subresource_filter/core/common/activation_decision.h"
 #include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -22,9 +21,7 @@
 // Class that manages interaction between interaction between the
 // per-navigation/per-tab subresource filter objects (i.e., the throttles and
 // throttle manager) and the per-profile objects (e.g., content settings).
-class ProfileInteractionManager
-    : public content::WebContentsObserver,
-      public SubresourceFilterSafeBrowsingActivationThrottle::Delegate {
+class ProfileInteractionManager : public content::WebContentsObserver {
  public:
   ProfileInteractionManager(content::WebContents* web_contents,
                             SubresourceFilterProfileContext* profile_context);
@@ -46,11 +43,19 @@
   void OnAdsViolationTriggered(content::RenderFrameHost* rfh,
                                mojom::AdsViolation triggered_violation);
 
-  // SubresourceFilterSafeBrowsingActivationThrottle::Delegate:
+  // Called when the initial activation decision has been computed by the
+  // safe browsing activation throttle. This object then applies any adjustments
+  // based on relevant state of the Profile (e.g., content settings). Returns
+  // the effective activation for this navigation.
+  //
+  // Note: |decision| is guaranteed to be non-nullptr, and can be modified by
+  // this method if any decision changes.
+  //
+  // Precondition: The navigation must be a main frame navigation.
   mojom::ActivationLevel OnPageActivationComputed(
       content::NavigationHandle* navigation_handle,
       mojom::ActivationLevel initial_activation_level,
-      ActivationDecision* decision) override;
+      ActivationDecision* decision);
 
  private:
   // Unowned and must outlive this object.
diff --git a/components/subresource_filter/content/browser/subresource_filter_client.h b/components/subresource_filter/content/browser/subresource_filter_client.h
index cdd3b9e..2b4e80d 100644
--- a/components/subresource_filter/content/browser/subresource_filter_client.h
+++ b/components/subresource_filter/content/browser/subresource_filter_client.h
@@ -6,8 +6,15 @@
 #define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
 
 #include "base/memory/scoped_refptr.h"
+#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
+#include "components/subresource_filter/core/common/activation_decision.h"
 #include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+class NavigationHandle;
+}  // namespace content
 
 namespace safe_browsing {
 class SafeBrowsingDatabaseManager;
@@ -15,8 +22,6 @@
 
 namespace subresource_filter {
 
-class ProfileInteractionManager;
-
 class SubresourceFilterClient {
  public:
   virtual ~SubresourceFilterClient() = default;
@@ -25,6 +30,20 @@
   // blocked. This method will be called at most once per main-frame navigation.
   virtual void ShowNotification() = 0;
 
+  // Called when the activation decision is otherwise completely computed by the
+  // subresource filter. At this point, the embedder still has a chance to
+  // alter the effective activation. Returns the effective activation for this
+  // navigation.
+  //
+  // Note: |decision| is guaranteed to be non-nullptr, and can be modified by
+  // the embedder if any decision changes.
+  //
+  // Precondition: The navigation must be a main frame navigation.
+  virtual mojom::ActivationLevel OnPageActivationComputed(
+      content::NavigationHandle* navigation_handle,
+      mojom::ActivationLevel initial_activation_level,
+      subresource_filter::ActivationDecision* decision) = 0;
+
   // Called on the subresource filter client when an ads violation is detected.
   virtual void OnAdsViolationTriggered(
       content::RenderFrameHost* rfh,
@@ -35,14 +54,6 @@
   virtual const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
   GetSafeBrowsingDatabaseManager() = 0;
 
-  // Returns the ProfileInteractionManager instance associated with this
-  // client, or null if there is no such instance.
-  // TODO(crbug.com/1116095): Have ContentSubresourceFilterThrottleManager
-  // create and own this object internally once ChromeSubresourceFilterClient no
-  // longer calls into it, replacing this method with a getter for
-  // SubresourceFilterProfileContext.
-  virtual ProfileInteractionManager* GetProfileInteractionManager() = 0;
-
   // Invoked when the user has requested a reload of a page with blocked ads
   // (e.g., via an infobar).
   virtual void OnReloadRequested() = 0;
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
index 6a6d09b..3f444aa 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
@@ -17,6 +17,7 @@
 #include "components/subresource_filter/content/browser/content_activation_list_utils.h"
 #include "components/subresource_filter/content/browser/devtools_interaction_tracker.h"
 #include "components/subresource_filter/content/browser/navigation_console_logger.h"
+#include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
 #include "components/subresource_filter/core/browser/subresource_filter_constants.h"
@@ -63,7 +64,7 @@
 SubresourceFilterSafeBrowsingActivationThrottle::
     SubresourceFilterSafeBrowsingActivationThrottle(
         content::NavigationHandle* handle,
-        Delegate* delegate,
+        SubresourceFilterClient* client,
         scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
         scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
             database_manager)
@@ -75,7 +76,7 @@
                            io_task_runner_,
                            base::ThreadTaskRunnerHandle::Get()),
                        base::OnTaskRunnerDeleter(io_task_runner_)),
-      delegate_(delegate) {
+      client_(client) {
   DCHECK(handle->IsInMainFrame());
 
   CheckCurrentUrl();
@@ -204,11 +205,9 @@
     activation_decision = ActivationDecision::FORCED_ACTIVATION;
   }
 
-  // Let the delegate adjust the activation decision if present.
-  if (delegate_) {
-    activation_level = delegate_->OnPageActivationComputed(
-        navigation_handle(), activation_level, &activation_decision);
-  }
+  // Let the embedder get the last word when it comes to activation level.
+  activation_level = client_->OnPageActivationComputed(
+      navigation_handle(), activation_level, &activation_decision);
 
   LogMetricsOnChecksComplete(selection.matched_list, activation_decision,
                              activation_level);
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
index 43e42b8..b3fc830 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
@@ -26,6 +26,8 @@
 
 namespace subresource_filter {
 
+class SubresourceFilterClient;
+
 // Enum representing a position in the redirect chain. These values are
 // persisted to logs. Entries should not be renumbered and numeric values should
 // never be reused.
@@ -44,32 +46,9 @@
       public base::SupportsWeakPtr<
           SubresourceFilterSafeBrowsingActivationThrottle> {
  public:
-  // Interface that allows the client of this class to adjust activation
-  // decisions if/as desired.
-  class Delegate {
-   public:
-    virtual ~Delegate() = default;
-
-    // Called when the initial activation decision has been computed by the
-    // safe browsing activation throttle. Returns
-    // the effective activation for this navigation.
-    //
-    // Note: |decision| is guaranteed to be non-nullptr, and can be modified by
-    // this method if any decision changes.
-    //
-    // Precondition: The navigation must be a main frame navigation.
-    virtual mojom::ActivationLevel OnPageActivationComputed(
-        content::NavigationHandle* navigation_handle,
-        mojom::ActivationLevel initial_activation_level,
-        ActivationDecision* decision) = 0;
-  };
-
-  // |delegate| is allowed to be null, in which case the client creating this
-  // throttle will not be able to adjust activation decisions made by the
-  // throttle.
   SubresourceFilterSafeBrowsingActivationThrottle(
       content::NavigationHandle* handle,
-      Delegate* delegate,
+      SubresourceFilterClient* client,
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
       scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
           database_manager);
@@ -131,8 +110,8 @@
                   base::OnTaskRunnerDeleter>
       database_client_;
 
-  // May be null. If non-null, must outlive this class.
-  Delegate* delegate_;
+  // Must outlive this class.
+  SubresourceFilterClient* client_;
 
   // Set to TimeTicks::Now() when the navigation is deferred in
   // WillProcessResponse. If deferral was not necessary, will remain null.
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
index a86533d..08f1cc5 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -24,7 +24,6 @@
 #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
 #include "components/subresource_filter/content/browser/devtools_interaction_tracker.h"
 #include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
-#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
@@ -70,17 +69,11 @@
     "SubresourceFilter.PageLoad.ActivationList";
 const char kSubresourceFilterActionsHistogram[] = "SubresourceFilter.Actions2";
 
-class TestSafeBrowsingActivationThrottleDelegate
-    : public SubresourceFilterSafeBrowsingActivationThrottle::Delegate {
+class MockSubresourceFilterClient : public SubresourceFilterClient {
  public:
-  TestSafeBrowsingActivationThrottleDelegate() = default;
-  ~TestSafeBrowsingActivationThrottleDelegate() override = default;
-  TestSafeBrowsingActivationThrottleDelegate(
-      const TestSafeBrowsingActivationThrottleDelegate&) = delete;
-  TestSafeBrowsingActivationThrottleDelegate& operator=(
-      const TestSafeBrowsingActivationThrottleDelegate&) = delete;
+  MockSubresourceFilterClient() = default;
+  ~MockSubresourceFilterClient() override = default;
 
-  // SubresourceFilterSafeBrowsingActivationThrottle::Delegate:
   mojom::ActivationLevel OnPageActivationComputed(
       content::NavigationHandle* handle,
       mojom::ActivationLevel effective_level,
@@ -95,6 +88,15 @@
     return effective_level;
   }
 
+  MOCK_METHOD0(ShowNotification, void());
+  MOCK_METHOD2(OnAdsViolationTriggered,
+               void(content::RenderFrameHost*,
+                    subresource_filter::mojom::AdsViolation));
+  MOCK_METHOD0(
+      GetSafeBrowsingDatabaseManager,
+      const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>());
+  MOCK_METHOD0(OnReloadRequested, void());
+
   void AllowlistInCurrentWebContents(const GURL& url) {
     ASSERT_TRUE(url.SchemeIsHTTPOrHTTPS());
     allowlisted_hosts_.insert(url.host());
@@ -104,25 +106,7 @@
 
  private:
   std::set<std::string> allowlisted_hosts_;
-};
 
-class MockSubresourceFilterClient : public SubresourceFilterClient {
- public:
-  MockSubresourceFilterClient() = default;
-  ~MockSubresourceFilterClient() override = default;
-
-  MOCK_METHOD0(ShowNotification, void());
-  MOCK_METHOD2(OnAdsViolationTriggered,
-               void(content::RenderFrameHost*,
-                    subresource_filter::mojom::AdsViolation));
-  MOCK_METHOD0(
-      GetSafeBrowsingDatabaseManager,
-      const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>());
-  MOCK_METHOD0(GetProfileInteractionManager,
-               subresource_filter::ProfileInteractionManager*());
-  MOCK_METHOD0(OnReloadRequested, void());
-
- private:
   DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterClient);
 };
 
@@ -229,7 +213,7 @@
     if (navigation_handle->IsInMainFrame()) {
       navigation_handle->RegisterThrottleForTesting(
           std::make_unique<SubresourceFilterSafeBrowsingActivationThrottle>(
-              navigation_handle, delegate(), test_io_task_runner_,
+              navigation_handle, client(), test_io_task_runner_,
               fake_safe_browsing_database_));
     }
     std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
@@ -353,7 +337,6 @@
 
   MockSubresourceFilterClient* client() { return client_; }
 
-  TestSafeBrowsingActivationThrottleDelegate* delegate() { return &delegate_; }
   base::TestMockTimeTaskRunner* test_io_task_runner() const {
     return test_io_task_runner_.get();
   }
@@ -369,7 +352,6 @@
   testing::TestRulesetCreator test_ruleset_creator_;
   testing::TestRulesetPair test_ruleset_pair_;
 
-  TestSafeBrowsingActivationThrottleDelegate delegate_;
   std::unique_ptr<VerifiedRulesetDealer::Handle> ruleset_dealer_;
 
   std::unique_ptr<ContentSubresourceFilterThrottleManager> throttle_manager_;
@@ -537,7 +519,7 @@
             *observer()->GetPageActivationForLastCommittedLoad());
 
   // Allowlisting occurs last, so the decision should still be DISABLED.
-  delegate()->AllowlistInCurrentWebContents(url);
+  client()->AllowlistInCurrentWebContents(url);
   SimulateNavigateAndCommit({url}, main_rfh());
   EXPECT_EQ(mojom::ActivationLevel::kDisabled,
             *observer()->GetPageActivationForLastCommittedLoad());
@@ -810,7 +792,7 @@
   EXPECT_EQ(test_data.expected_activation_level,
             *observer()->GetPageActivationForLastCommittedLoad());
   if (test_data.url_matches_activation_list) {
-    delegate()->AllowlistInCurrentWebContents(test_url);
+    client()->AllowlistInCurrentWebContents(test_url);
     SimulateNavigateAndCommit({test_url}, main_rfh());
     EXPECT_EQ(mojom::ActivationLevel::kDisabled,
               *observer()->GetPageActivationForLastCommittedLoad());
diff --git a/components/sync/base/invalidation_adapter.cc b/components/sync/base/invalidation_adapter.cc
index ab4c167..00f2663 100644
--- a/components/sync/base/invalidation_adapter.cc
+++ b/components/sync/base/invalidation_adapter.cc
@@ -6,10 +6,11 @@
 
 namespace syncer {
 
-InvalidationAdapter::InvalidationAdapter(const Invalidation& invalidation)
+InvalidationAdapter::InvalidationAdapter(
+    const invalidation::Invalidation& invalidation)
     : invalidation_(invalidation) {}
 
-InvalidationAdapter::~InvalidationAdapter() {}
+InvalidationAdapter::~InvalidationAdapter() = default;
 
 bool InvalidationAdapter::IsUnknownVersion() const {
   return invalidation_.is_unknown_version();
diff --git a/components/sync/base/invalidation_adapter.h b/components/sync/base/invalidation_adapter.h
index 07a02023..c18881f 100644
--- a/components/sync/base/invalidation_adapter.h
+++ b/components/sync/base/invalidation_adapter.h
@@ -17,7 +17,7 @@
 // Wraps a Invalidation in the InvalidationInterface.
 class InvalidationAdapter : public InvalidationInterface {
  public:
-  explicit InvalidationAdapter(const Invalidation& invalidation);
+  explicit InvalidationAdapter(const invalidation::Invalidation& invalidation);
   ~InvalidationAdapter() override;
 
   // Implementation of InvalidationInterface.
@@ -28,7 +28,7 @@
   void Drop() override;
 
  private:
-  Invalidation invalidation_;
+  invalidation::Invalidation invalidation_;
 };
 
 }  // namespace syncer
diff --git a/components/sync/base/invalidation_helper.cc b/components/sync/base/invalidation_helper.cc
index ff75b13..57ef035 100644
--- a/components/sync/base/invalidation_helper.cc
+++ b/components/sync/base/invalidation_helper.cc
@@ -10,10 +10,10 @@
 
 namespace syncer {
 
-TopicSet ModelTypeSetToTopicSet(ModelTypeSet model_types) {
-  TopicSet topics;
+invalidation::TopicSet ModelTypeSetToTopicSet(ModelTypeSet model_types) {
+  invalidation::TopicSet topics;
   for (ModelType type : model_types) {
-    Topic topic;
+    invalidation::Topic topic;
     if (!RealModelTypeToNotificationType(type, &topic)) {
       DLOG(WARNING) << "Invalid model type " << type;
       continue;
diff --git a/components/sync/base/invalidation_helper.h b/components/sync/base/invalidation_helper.h
index 9ff9b22..f51bd91 100644
--- a/components/sync/base/invalidation_helper.h
+++ b/components/sync/base/invalidation_helper.h
@@ -10,7 +10,7 @@
 
 namespace syncer {
 
-TopicSet ModelTypeSetToTopicSet(ModelTypeSet model_types);
+invalidation::TopicSet ModelTypeSetToTopicSet(ModelTypeSet model_types);
 
 }  // namespace syncer
 
diff --git a/components/sync/driver/glue/sync_engine_backend.cc b/components/sync/driver/glue/sync_engine_backend.cc
index d6dd6d2..a8d46f9 100644
--- a/components/sync/driver/glue/sync_engine_backend.cc
+++ b/components/sync/driver/glue/sync_engine_backend.cc
@@ -176,13 +176,15 @@
   }
 }
 
-void SyncEngineBackend::DoOnInvalidatorStateChange(InvalidatorState state) {
+void SyncEngineBackend::DoOnInvalidatorStateChange(
+    invalidation::InvalidatorState state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  sync_manager_->SetInvalidatorEnabled(state == INVALIDATIONS_ENABLED);
+  sync_manager_->SetInvalidatorEnabled(state ==
+                                       invalidation::INVALIDATIONS_ENABLED);
 }
 
 bool SyncEngineBackend::ShouldIgnoreRedundantInvalidation(
-    const Invalidation& invalidation,
+    const invalidation::Invalidation& invalidation,
     ModelType type) {
   bool fcm_invalidation = base::FeatureList::IsEnabled(
       invalidation::switches::kFCMInvalidationsForSyncDontCheckVersion);
@@ -204,19 +206,19 @@
 }
 
 void SyncEngineBackend::DoOnIncomingInvalidation(
-    const TopicInvalidationMap& invalidation_map) {
+    const invalidation::TopicInvalidationMap& invalidation_map) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  for (const Topic& topic : invalidation_map.GetTopics()) {
+  for (const invalidation::Topic& topic : invalidation_map.GetTopics()) {
     ModelType type;
     if (!NotificationTypeToRealModelType(topic, &type)) {
       DLOG(WARNING) << "Notification has invalid topic: " << topic;
     } else {
       UMA_HISTOGRAM_ENUMERATION("Sync.InvalidationPerModelType",
                                 ModelTypeHistogramValue(type));
-      SingleObjectInvalidationSet invalidation_set =
+      invalidation::SingleObjectInvalidationSet invalidation_set =
           invalidation_map.ForTopic(topic);
-      for (Invalidation invalidation : invalidation_set) {
+      for (invalidation::Invalidation invalidation : invalidation_set) {
         if (ShouldIgnoreRedundantInvalidation(invalidation, type)) {
           continue;
         }
diff --git a/components/sync/driver/glue/sync_engine_backend.h b/components/sync/driver/glue/sync_engine_backend.h
index 04626ff..a51d1a4 100644
--- a/components/sync/driver/glue/sync_engine_backend.h
+++ b/components/sync/driver/glue/sync_engine_backend.h
@@ -62,10 +62,11 @@
   void OnSyncStatusChanged(const SyncStatus& status) override;
 
   // Forwards an invalidation state change to the sync manager.
-  void DoOnInvalidatorStateChange(InvalidatorState state);
+  void DoOnInvalidatorStateChange(invalidation::InvalidatorState state);
 
   // Forwards an invalidation to the sync manager.
-  void DoOnIncomingInvalidation(const TopicInvalidationMap& invalidation_map);
+  void DoOnIncomingInvalidation(
+      const invalidation::TopicInvalidationMap& invalidation_map);
 
   // Note:
   //
@@ -163,8 +164,9 @@
 
   // For the olg tango based invalidations method returns true if the
   // invalidation has version lower than last seen version for this datatype.
-  bool ShouldIgnoreRedundantInvalidation(const Invalidation& invalidation,
-                                         ModelType Type);
+  bool ShouldIgnoreRedundantInvalidation(
+      const invalidation::Invalidation& invalidation,
+      ModelType Type);
 
   void LoadAndConnectNigoriController();
 
diff --git a/components/sync/driver/glue/sync_engine_impl.cc b/components/sync/driver/glue/sync_engine_impl.cc
index c03835b3..4aecd1f 100644
--- a/components/sync/driver/glue/sync_engine_impl.cc
+++ b/components/sync/driver/glue/sync_engine_impl.cc
@@ -343,14 +343,15 @@
   host_->OnMigrationNeededForTypes(types);
 }
 
-void SyncEngineImpl::OnInvalidatorStateChange(InvalidatorState state) {
+void SyncEngineImpl::OnInvalidatorStateChange(
+    invalidation::InvalidatorState state) {
   sync_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&SyncEngineBackend::DoOnInvalidatorStateChange,
                                 backend_, state));
 }
 
 void SyncEngineImpl::OnIncomingInvalidation(
-    const TopicInvalidationMap& invalidation_map) {
+    const invalidation::TopicInvalidationMap& invalidation_map) {
   sync_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&SyncEngineBackend::DoOnIncomingInvalidation,
                                 backend_, invalidation_map));
diff --git a/components/sync/driver/glue/sync_engine_impl.h b/components/sync/driver/glue/sync_engine_impl.h
index 3da67552..ebde203 100644
--- a/components/sync/driver/glue/sync_engine_impl.h
+++ b/components/sync/driver/glue/sync_engine_impl.h
@@ -52,7 +52,7 @@
 // The only real implementation of the SyncEngine. See that interface's
 // definition for documentation of public methods.
 class SyncEngineImpl : public SyncEngine,
-                       public InvalidationHandler,
+                       public invalidation::InvalidationHandler,
                        public InvalidationsListener {
  public:
   using Status = SyncStatus;
@@ -98,9 +98,9 @@
   void GetNigoriNodeForDebugging(AllNodesCallback callback) override;
 
   // InvalidationHandler implementation.
-  void OnInvalidatorStateChange(InvalidatorState state) override;
+  void OnInvalidatorStateChange(invalidation::InvalidatorState state) override;
   void OnIncomingInvalidation(
-      const TopicInvalidationMap& invalidation_map) override;
+      const invalidation::TopicInvalidationMap& invalidation_map) override;
   std::string GetOwnerName() const override;
   void OnInvalidatorClientIdChange(const std::string& client_id) override;
 
diff --git a/components/sync/driver/glue/sync_engine_impl_unittest.cc b/components/sync/driver/glue/sync_engine_impl_unittest.cc
index ee8cea7..e40c6a09 100644
--- a/components/sync/driver/glue/sync_engine_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_engine_impl_unittest.cc
@@ -145,18 +145,18 @@
   ~MockInvalidationService() override = default;
   MOCK_METHOD(void,
               RegisterInvalidationHandler,
-              (syncer::InvalidationHandler * handler),
+              (invalidation::InvalidationHandler * handler),
               (override));
   MOCK_METHOD(bool,
               UpdateInterestedTopics,
-              (syncer::InvalidationHandler * handler,
-               const syncer::TopicSet& topics),
+              (invalidation::InvalidationHandler * handler,
+               const invalidation::TopicSet& topics),
               (override));
   MOCK_METHOD(void,
               UnregisterInvalidationHandler,
-              (syncer::InvalidationHandler * handler),
+              (invalidation::InvalidationHandler * handler),
               (override));
-  MOCK_METHOD(syncer::InvalidatorState,
+  MOCK_METHOD(invalidation::InvalidatorState,
               GetInvalidatorState,
               (),
               (const override));
@@ -619,7 +619,8 @@
   ConfigureDataTypes();
 
   // At shutdown, we clear the registered invalidation ids.
-  EXPECT_CALL(invalidator_, UpdateInterestedTopics(backend_.get(), TopicSet()));
+  EXPECT_CALL(invalidator_,
+              UpdateInterestedTopics(backend_.get(), invalidation::TopicSet()));
 }
 
 TEST_F(SyncEngineImplTest, WhenEnabledTypesStayDisabled) {
@@ -636,7 +637,8 @@
   ConfigureDataTypes();
 
   // At shutdown, we clear the registered invalidation ids.
-  EXPECT_CALL(invalidator_, UpdateInterestedTopics(backend_.get(), TopicSet()));
+  EXPECT_CALL(invalidator_,
+              UpdateInterestedTopics(backend_.get(), invalidation::TopicSet()));
 }
 
 TEST_F(SyncEngineImplTest,
@@ -664,7 +666,8 @@
   backend_->SetInvalidationsForSessionsEnabled(false);
 
   // At shutdown, we clear the registered invalidation ids.
-  EXPECT_CALL(invalidator_, UpdateInterestedTopics(backend_.get(), TopicSet()));
+  EXPECT_CALL(invalidator_,
+              UpdateInterestedTopics(backend_.get(), invalidation::TopicSet()));
 }
 
 // Regression test for crbug.com/1019956.
@@ -716,7 +719,8 @@
   ConfigureDataTypes();
 
   // At shutdown, we clear the registered invalidation ids.
-  EXPECT_CALL(invalidator_, UpdateInterestedTopics(backend_.get(), TopicSet()));
+  EXPECT_CALL(invalidator_,
+              UpdateInterestedTopics(backend_.get(), invalidation::TopicSet()));
 }
 
 TEST_F(SyncEngineImplWithSyncInvalidationsForWalletAndOfferTest,
@@ -726,7 +730,8 @@
   // Since the old invalidations system is not being used anymore (based on the
   // enabled feature flags), SyncEngine should call the (old) invalidator with
   // an empty TopicSet upon initialization.
-  EXPECT_CALL(invalidator_, UpdateInterestedTopics(_, TopicSet()));
+  EXPECT_CALL(invalidator_,
+              UpdateInterestedTopics(_, invalidation::TopicSet()));
   InitializeBackend(/*expect_success=*/true);
 
   EXPECT_CALL(invalidator_, UpdateInterestedTopics).Times(0);
diff --git a/components/thin_webview/internal/thin_webview.cc b/components/thin_webview/internal/thin_webview.cc
index 208b5028..a9720e2 100644
--- a/components/thin_webview/internal/thin_webview.cc
+++ b/components/thin_webview/internal/thin_webview.cc
@@ -47,13 +47,9 @@
   delete this;
 }
 
-void ThinWebView::RenderFrameCreated(
-    content::RenderFrameHost* render_frame_host) {
-  // Only update the browser controls state for the main frame.
-  if (render_frame_host->GetParent())
-    return;
+void ThinWebView::DocumentAvailableInMainFrame() {
   // Disable browser controls when used for thin webview.
-  render_frame_host->UpdateBrowserControlsState(
+  web_contents_->GetMainFrame()->UpdateBrowserControlsState(
       cc::BrowserControlsState::kHidden, cc::BrowserControlsState::kHidden,
       false);
 }
diff --git a/components/thin_webview/internal/thin_webview.h b/components/thin_webview/internal/thin_webview.h
index 93db88a..9976888 100644
--- a/components/thin_webview/internal/thin_webview.h
+++ b/components/thin_webview/internal/thin_webview.h
@@ -46,7 +46,7 @@
 
  private:
   // content::WebContentsObserver overrides:
-  void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+  void DocumentAvailableInMainFrame() override;
 
   void SetWebContents(
       content::WebContents* web_contents,
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc
index 7bc16b8..0c57810 100644
--- a/components/translate/content/browser/content_translate_driver.cc
+++ b/components/translate/content/browser/content_translate_driver.cc
@@ -213,7 +213,7 @@
   // If not a reload, return.
   if (!ui::PageTransitionCoreTypeIs(entry->GetTransitionType(),
                                     ui::PAGE_TRANSITION_RELOAD) &&
-      load_details.type != content::NAVIGATION_TYPE_SAME_PAGE) {
+      load_details.type != content::NAVIGATION_TYPE_SAME_ENTRY) {
     return;
   }
 
diff --git a/components/translate/content/browser/per_frame_content_translate_driver.cc b/components/translate/content/browser/per_frame_content_translate_driver.cc
index e8a6f8a..58a9cc3 100644
--- a/components/translate/content/browser/per_frame_content_translate_driver.cc
+++ b/components/translate/content/browser/per_frame_content_translate_driver.cc
@@ -234,7 +234,7 @@
   // If not a reload, return.
   if (!ui::PageTransitionCoreTypeIs(entry->GetTransitionType(),
                                     ui::PAGE_TRANSITION_RELOAD) &&
-      load_details.type != content::NAVIGATION_TYPE_SAME_PAGE) {
+      load_details.type != content::NAVIGATION_TYPE_SAME_ENTRY) {
     return;
   }
 
diff --git a/components/ui_devtools/css_agent.cc b/components/ui_devtools/css_agent.cc
index efdbdf5..a4048bb 100644
--- a/components/ui_devtools/css_agent.cc
+++ b/components/ui_devtools/css_agent.cc
@@ -51,7 +51,7 @@
 std::unique_ptr<Array<int>> BuildDefaultMatchingSelectors() {
   auto matching_selectors = std::make_unique<Array<int>>();
 
-  // Add index 0 to matching delectors array, so frontend uses the class mame
+  // Add index 0 to matching selectors array, so frontend uses the class name
   // from the selectors array as the header for the properties section
   matching_selectors->emplace_back(0);
   return matching_selectors;
@@ -272,21 +272,21 @@
     if (!ui_element)
       return Response::ServerError("Node id not found");
     // Handle setting properties from metadata for View.
-    if (ui_element->type() == VIEW)
-      ui_element->SetPropertiesFromString(edit->getText());
+    if (ui_element->type() != VIEW ||
+        !ui_element->SetPropertiesFromString(edit->getText())) {
+      gfx::Rect updated_bounds;
+      bool visible = false;
+      if (!GetPropertiesForUIElement(ui_element, &updated_bounds, &visible))
+        return NodeNotFoundError(node_id);
 
-    gfx::Rect updated_bounds;
-    bool visible = false;
-    if (!GetPropertiesForUIElement(ui_element, &updated_bounds, &visible))
-      return NodeNotFoundError(node_id);
+      Response response(
+          ParseProperties(edit->getText(), &updated_bounds, &visible));
+      if (!response.IsSuccess())
+        return response;
 
-    Response response(
-        ParseProperties(edit->getText(), &updated_bounds, &visible));
-    if (!response.IsSuccess())
-      return response;
-
-    if (!SetPropertiesForUIElement(ui_element, updated_bounds, visible))
-      return NodeNotFoundError(node_id);
+      if (!SetPropertiesForUIElement(ui_element, updated_bounds, visible))
+        return NodeNotFoundError(node_id);
+    }
 
     updated_styles->emplace_back(BuildCSSStyle(
         edit->getStyleSheetId(), GetClassPropertiesWithBounds(ui_element)
diff --git a/components/ui_devtools/views/view_element.cc b/components/ui_devtools/views/view_element.cc
index bee4ca7..883e321 100644
--- a/components/ui_devtools/views/view_element.cc
+++ b/components/ui_devtools/views/view_element.cc
@@ -4,6 +4,8 @@
 
 #include "components/ui_devtools/views/view_element.h"
 
+#include <algorithm>
+
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/ui_devtools/Protocol.h"
@@ -94,23 +96,6 @@
   std::vector<UIElement::UIProperty> class_properties;
   views::metadata::ClassMetaData* metadata = view_->GetClassMetaData();
   for (auto member = metadata->begin(); member != metadata->end(); member++) {
-    if (member.GetCurrentCollectionName() == "View" &&
-        class_properties.empty()) {
-      gfx::Rect bounds = view_->bounds();
-      class_properties.emplace_back("x", base::NumberToString(bounds.x()));
-      class_properties.emplace_back("y", base::NumberToString(bounds.y()));
-      class_properties.emplace_back("width",
-                                    base::NumberToString(bounds.width()));
-      class_properties.emplace_back("height",
-                                    base::NumberToString(bounds.height()));
-      class_properties.emplace_back("is-drawn",
-                                    view_->IsDrawn() ? "true" : "false");
-      base::string16 description = view_->GetTooltipText(gfx::Point());
-      if (!description.empty())
-        class_properties.emplace_back("tooltip",
-                                      base::UTF16ToUTF8(description));
-    }
-
     // Check if type is SkColor and add "--" to property name so that DevTools
     // frontend will interpret this field as a color. Also convert SkColor value
     // to rgba string.
@@ -182,12 +167,13 @@
     }
 
     // Since DevTools frontend doesn't check the value, we do a sanity check
-    // based on its type here.
-    if (member->member_type() == "bool") {
-      if (property_value != "true" && property_value != "false") {
-        // Ignore the value.
-        continue;
-      }
+    // based on the allowed values specified in the metadata.
+    auto valid_values = member->GetValidValues();
+    if (!valid_values.empty() &&
+        std::find(valid_values.begin(), valid_values.end(),
+                  base::UTF8ToUTF16(property_value)) == valid_values.end()) {
+      // Ignore the value.
+      continue;
     }
 
     DCHECK(!!(member->GetPropertyFlags() &
diff --git a/components/ui_devtools/views/view_element_unittest.cc b/components/ui_devtools/views/view_element_unittest.cc
index 588080e..02ec280 100644
--- a/components/ui_devtools/views/view_element_unittest.cc
+++ b/components/ui_devtools/views/view_element_unittest.cc
@@ -203,7 +203,7 @@
   // the vector.
   DCHECK_EQ(indices.first, 0U);
 
-  indices = GetPropertyIndices(element(), "tooltip");
+  indices = GetPropertyIndices(element(), "Tooltip");
   // The tooltip property should be in the second ClassProperties object in the
   // vector.
   DCHECK_EQ(indices.first, 1U);
@@ -211,7 +211,7 @@
   std::vector<UIElement::UIProperty> ui_props =
       props[indices.first].properties_;
 
-  EXPECT_EQ(ui_props[indices.second].name_, "tooltip");
+  EXPECT_EQ(ui_props[indices.second].name_, "Tooltip");
   EXPECT_EQ(ui_props[indices.second].value_, "This is the tooltip");
 }
 
diff --git a/components/update_client/update_query_params.cc b/components/update_client/update_query_params.cc
index 2d9d8ee..9c8b16a 100644
--- a/components/update_client/update_query_params.cc
+++ b/components/update_client/update_query_params.cc
@@ -32,9 +32,9 @@
     "win";
 #elif defined(OS_ANDROID)
     "android";
-#elif BUILDFLAG(IS_CHROMEOS_ASH)
+#elif BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
     "cros";
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif defined(OS_LINUX)
     "linux";
 #elif defined(OS_FUCHSIA)
     "fuchsia";
diff --git a/components/webapps/BUILD.gn b/components/webapps/browser/BUILD.gn
similarity index 97%
rename from components/webapps/BUILD.gn
rename to components/webapps/browser/BUILD.gn
index 2c6bb1d..5dcb5af5 100644
--- a/components/webapps/BUILD.gn
+++ b/components/webapps/browser/BUILD.gn
@@ -4,7 +4,7 @@
 
 assert(!is_ios)
 
-source_set("webapps") {
+source_set("browser") {
   sources = [
     "installable/installable_data.cc",
     "installable/installable_data.h",
@@ -76,7 +76,7 @@
     "installable/fake_installable_manager.h",
   ]
   deps = [
-    ":webapps",
+    ":browser",
     "//base",
     "//skia",
     "//url",
@@ -90,7 +90,7 @@
     "installable/installable_task_queue_unittest.cc",
   ]
   deps = [
-    ":webapps",
+    ":browser",
     "//base",
     "//base/test:test_support",
     "//content/public/common",
diff --git a/components/webapps/DEPS b/components/webapps/browser/DEPS
similarity index 100%
rename from components/webapps/DEPS
rename to components/webapps/browser/DEPS
diff --git a/components/webapps/android/BUILD.gn b/components/webapps/browser/android/BUILD.gn
similarity index 98%
rename from components/webapps/android/BUILD.gn
rename to components/webapps/browser/android/BUILD.gn
index 13324b3..3f7364f0 100644
--- a/components/webapps/android/BUILD.gn
+++ b/components/webapps/browser/android/BUILD.gn
@@ -61,7 +61,7 @@
   ]
   deps = [
     "//base",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//testing/gtest",
     "//third_party/blink/public/common:common",
     "//third_party/blink/public/mojom:mojom_platform",
diff --git a/components/webapps/android/DEPS b/components/webapps/browser/android/DEPS
similarity index 100%
rename from components/webapps/android/DEPS
rename to components/webapps/browser/android/DEPS
diff --git a/components/webapps/android/add_to_homescreen_params.cc b/components/webapps/browser/android/add_to_homescreen_params.cc
similarity index 71%
rename from components/webapps/android/add_to_homescreen_params.cc
rename to components/webapps/browser/android/add_to_homescreen_params.cc
index d7061f2f..4984755 100644
--- a/components/webapps/android/add_to_homescreen_params.cc
+++ b/components/webapps/browser/android/add_to_homescreen_params.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/add_to_homescreen_params.h"
+#include "components/webapps/browser/android/add_to_homescreen_params.h"
 
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 
 namespace webapps {
 
diff --git a/components/webapps/android/add_to_homescreen_params.h b/components/webapps/browser/android/add_to_homescreen_params.h
similarity index 76%
rename from components/webapps/android/add_to_homescreen_params.h
rename to components/webapps/browser/android/add_to_homescreen_params.h
index c14c9cc..8c71d9f 100644
--- a/components/webapps/android/add_to_homescreen_params.h
+++ b/components/webapps/browser/android/add_to_homescreen_params.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_WEBAPPS_ANDROID_ADD_TO_HOMESCREEN_PARAMS_H_
-#define COMPONENTS_WEBAPPS_ANDROID_ADD_TO_HOMESCREEN_PARAMS_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_ADD_TO_HOMESCREEN_PARAMS_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_ADD_TO_HOMESCREEN_PARAMS_H_
 
 #include <memory>
 #include <string>
 
 #include "base/android/scoped_java_ref.h"
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 namespace webapps {
@@ -40,4 +40,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_ANDROID_ADD_TO_HOMESCREEN_PARAMS_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_ADD_TO_HOMESCREEN_PARAMS_H_
diff --git a/components/webapps/android/features.cc b/components/webapps/browser/android/features.cc
similarity index 87%
rename from components/webapps/android/features.cc
rename to components/webapps/browser/android/features.cc
index ea8afc4..99ffb91 100644
--- a/components/webapps/android/features.cc
+++ b/components/webapps/browser/android/features.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/features.h"
+#include "components/webapps/browser/android/features.h"
 
 #include "base/feature_list.h"
 
diff --git a/components/webapps/android/features.h b/components/webapps/browser/android/features.h
similarity index 68%
rename from components/webapps/android/features.h
rename to components/webapps/browser/android/features.h
index 70055ce0..3c853b3 100644
--- a/components/webapps/android/features.h
+++ b/components/webapps/browser/android/features.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_WEBAPPS_ANDROID_FEATURES_H_
-#define COMPONENTS_WEBAPPS_ANDROID_FEATURES_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_FEATURES_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_FEATURES_H_
 
 namespace base {
 struct Feature;
@@ -16,4 +16,4 @@
 }  // namespace features
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_ANDROID_FEATURES_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_FEATURES_H_
diff --git a/components/webapps/android/installable/installable_ambient_badge_infobar.cc b/components/webapps/browser/android/installable/installable_ambient_badge_infobar.cc
similarity index 86%
rename from components/webapps/android/installable/installable_ambient_badge_infobar.cc
rename to components/webapps/browser/android/installable/installable_ambient_badge_infobar.cc
index bbb5441..1f388140 100644
--- a/components/webapps/android/installable/installable_ambient_badge_infobar.cc
+++ b/components/webapps/browser/android/installable/installable_ambient_badge_infobar.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/installable/installable_ambient_badge_infobar.h"
+#include "components/webapps/browser/android/installable/installable_ambient_badge_infobar.h"
 
 #include <utility>
 
 #include "base/android/jni_string.h"
 #include "base/bind.h"
-#include "components/webapps/android/installable/installable_ambient_badge_infobar_delegate.h"
-#include "components/webapps/android/webapps_jni_headers/InstallableAmbientBadgeInfoBar_jni.h"
+#include "components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.h"
+#include "components/webapps/browser/android/webapps_jni_headers/InstallableAmbientBadgeInfoBar_jni.h"
 #include "ui/gfx/android/java_bitmap.h"
 
 namespace webapps {
diff --git a/components/webapps/android/installable/installable_ambient_badge_infobar.h b/components/webapps/browser/android/installable/installable_ambient_badge_infobar.h
similarity index 80%
rename from components/webapps/android/installable/installable_ambient_badge_infobar.h
rename to components/webapps/browser/android/installable/installable_ambient_badge_infobar.h
index e27bdc4..a0c20e7 100644
--- a/components/webapps/android/installable/installable_ambient_badge_infobar.h
+++ b/components/webapps/browser/android/installable/installable_ambient_badge_infobar.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_WEBAPPS_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_H_
-#define COMPONENTS_WEBAPPS_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_H_
 
 #include <memory>
 
@@ -39,4 +39,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_H_
diff --git a/components/webapps/android/installable/installable_ambient_badge_infobar_delegate.cc b/components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.cc
similarity index 91%
rename from components/webapps/android/installable/installable_ambient_badge_infobar_delegate.cc
rename to components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.cc
index 827104ef..f16ca0aa 100644
--- a/components/webapps/android/installable/installable_ambient_badge_infobar_delegate.cc
+++ b/components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/installable/installable_ambient_badge_infobar_delegate.h"
+#include "components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.h"
 
 #include <memory>
 
@@ -11,9 +11,9 @@
 #include "base/metrics/field_trial_params.h"
 #include "components/infobars/content/content_infobar_manager.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/webapps/android/features.h"
-#include "components/webapps/android/installable/installable_ambient_badge_infobar.h"
-#include "components/webapps/webapps_client.h"
+#include "components/webapps/browser/android/features.h"
+#include "components/webapps/browser/android/installable/installable_ambient_badge_infobar.h"
+#include "components/webapps/browser/webapps_client.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace webapps {
diff --git a/components/webapps/android/installable/installable_ambient_badge_infobar_delegate.h b/components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.h
similarity index 89%
rename from components/webapps/android/installable/installable_ambient_badge_infobar_delegate.h
rename to components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.h
index a222d632..fb5a8351 100644
--- a/components/webapps/android/installable/installable_ambient_badge_infobar_delegate.h
+++ b/components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.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_WEBAPPS_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE_H_
-#define COMPONENTS_WEBAPPS_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE_H_
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -80,4 +80,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_INSTALLABLE_INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE_H_
diff --git a/components/webapps/android/java/res/mipmap-hdpi/shortcut_icon_shadow.png b/components/webapps/browser/android/java/res/mipmap-hdpi/shortcut_icon_shadow.png
similarity index 100%
rename from components/webapps/android/java/res/mipmap-hdpi/shortcut_icon_shadow.png
rename to components/webapps/browser/android/java/res/mipmap-hdpi/shortcut_icon_shadow.png
Binary files differ
diff --git a/components/webapps/android/java/res/mipmap-mdpi/shortcut_icon_shadow.png b/components/webapps/browser/android/java/res/mipmap-mdpi/shortcut_icon_shadow.png
similarity index 100%
rename from components/webapps/android/java/res/mipmap-mdpi/shortcut_icon_shadow.png
rename to components/webapps/browser/android/java/res/mipmap-mdpi/shortcut_icon_shadow.png
Binary files differ
diff --git a/components/webapps/android/java/res/mipmap-xhdpi/shortcut_icon_shadow.png b/components/webapps/browser/android/java/res/mipmap-xhdpi/shortcut_icon_shadow.png
similarity index 100%
rename from components/webapps/android/java/res/mipmap-xhdpi/shortcut_icon_shadow.png
rename to components/webapps/browser/android/java/res/mipmap-xhdpi/shortcut_icon_shadow.png
Binary files differ
diff --git a/components/webapps/android/java/res/mipmap-xxhdpi/shortcut_icon_shadow.png b/components/webapps/browser/android/java/res/mipmap-xxhdpi/shortcut_icon_shadow.png
similarity index 100%
rename from components/webapps/android/java/res/mipmap-xxhdpi/shortcut_icon_shadow.png
rename to components/webapps/browser/android/java/res/mipmap-xxhdpi/shortcut_icon_shadow.png
Binary files differ
diff --git a/components/webapps/android/java/res/mipmap-xxxhdpi/shortcut_icon_shadow.png b/components/webapps/browser/android/java/res/mipmap-xxxhdpi/shortcut_icon_shadow.png
similarity index 100%
rename from components/webapps/android/java/res/mipmap-xxxhdpi/shortcut_icon_shadow.png
rename to components/webapps/browser/android/java/res/mipmap-xxxhdpi/shortcut_icon_shadow.png
Binary files differ
diff --git a/components/webapps/android/java/res/values/dimens.xml b/components/webapps/browser/android/java/res/values/dimens.xml
similarity index 100%
rename from components/webapps/android/java/res/values/dimens.xml
rename to components/webapps/browser/android/java/res/values/dimens.xml
diff --git a/components/webapps/android/java/src/org/chromium/components/webapps/WebappsIconUtils.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/WebappsIconUtils.java
similarity index 100%
rename from components/webapps/android/java/src/org/chromium/components/webapps/WebappsIconUtils.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/WebappsIconUtils.java
diff --git a/components/webapps/android/java/src/org/chromium/components/webapps/WebappsUtils.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/WebappsUtils.java
similarity index 100%
rename from components/webapps/android/java/src/org/chromium/components/webapps/WebappsUtils.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/WebappsUtils.java
diff --git a/components/webapps/android/java/src/org/chromium/components/webapps/installable/InstallableAmbientBadgeInfoBar.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/installable/InstallableAmbientBadgeInfoBar.java
similarity index 100%
rename from components/webapps/android/java/src/org/chromium/components/webapps/installable/InstallableAmbientBadgeInfoBar.java
rename to components/webapps/browser/android/java/src/org/chromium/components/webapps/installable/InstallableAmbientBadgeInfoBar.java
diff --git a/components/webapps/android/shortcut_info.cc b/components/webapps/browser/android/shortcut_info.cc
similarity index 97%
rename from components/webapps/android/shortcut_info.cc
rename to components/webapps/browser/android/shortcut_info.cc
index 74d914a5..b232e81 100644
--- a/components/webapps/android/shortcut_info.cc
+++ b/components/webapps/browser/android/shortcut_info.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 
 #include "base/feature_list.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/webapps/android/webapps_icon_utils.h"
+#include "components/webapps/browser/android/webapps_icon_utils.h"
 #include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
 
 namespace webapps {
diff --git a/components/webapps/android/shortcut_info.h b/components/webapps/browser/android/shortcut_info.h
similarity index 96%
rename from components/webapps/android/shortcut_info.h
rename to components/webapps/browser/android/shortcut_info.h
index 8daf99b8..836def9b 100644
--- a/components/webapps/android/shortcut_info.h
+++ b/components/webapps/browser/android/shortcut_info.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_WEBAPPS_ANDROID_SHORTCUT_INFO_H_
-#define COMPONENTS_WEBAPPS_ANDROID_SHORTCUT_INFO_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_SHORTCUT_INFO_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_SHORTCUT_INFO_H_
 
 #include <stdint.h>
 
@@ -150,4 +150,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_ANDROID_SHORTCUT_INFO_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_SHORTCUT_INFO_H_
diff --git a/components/webapps/android/shortcut_info_unittest.cc b/components/webapps/browser/android/shortcut_info_unittest.cc
similarity index 97%
rename from components/webapps/android/shortcut_info_unittest.cc
rename to components/webapps/browser/android/shortcut_info_unittest.cc
index 6c49057..86b4075 100644
--- a/components/webapps/android/shortcut_info_unittest.cc
+++ b/components/webapps/browser/android/shortcut_info_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/shortcut_info.h"
+#include "components/webapps/browser/android/shortcut_info.h"
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/webapps/android/webapps_icon_utils.h"
+#include "components/webapps/browser/android/webapps_icon_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
diff --git a/components/webapps/android/webapps_icon_utils.cc b/components/webapps/browser/android/webapps_icon_utils.cc
similarity index 96%
rename from components/webapps/android/webapps_icon_utils.cc
rename to components/webapps/browser/android/webapps_icon_utils.cc
index 47df4c0..55f44e2 100644
--- a/components/webapps/android/webapps_icon_utils.cc
+++ b/components/webapps/browser/android/webapps_icon_utils.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/webapps_icon_utils.h"
+#include "components/webapps/browser/android/webapps_icon_utils.h"
 
 #include "base/android/build_info.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
-#include "components/webapps/android/webapps_jni_headers/WebappsIconUtils_jni.h"
+#include "components/webapps/browser/android/webapps_jni_headers/WebappsIconUtils_jni.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/color_analysis.h"
diff --git a/components/webapps/android/webapps_icon_utils.h b/components/webapps/browser/android/webapps_icon_utils.h
similarity index 90%
rename from components/webapps/android/webapps_icon_utils.h
rename to components/webapps/browser/android/webapps_icon_utils.h
index 2a5d8e4..f2ce24c 100644
--- a/components/webapps/android/webapps_icon_utils.h
+++ b/components/webapps/browser/android/webapps_icon_utils.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_WEBAPPS_ANDROID_WEBAPPS_ICON_UTILS_H_
-#define COMPONENTS_WEBAPPS_ANDROID_WEBAPPS_ICON_UTILS_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPPS_ICON_UTILS_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPPS_ICON_UTILS_H_
 
 #include "base/android/scoped_java_ref.h"
 
@@ -58,4 +58,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_ANDROID_WEBAPPS_ICON_UTILS_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPPS_ICON_UTILS_H_
diff --git a/components/webapps/android/webapps_utils.cc b/components/webapps/browser/android/webapps_utils.cc
similarity index 92%
rename from components/webapps/android/webapps_utils.cc
rename to components/webapps/browser/android/webapps_utils.cc
index c3d15f3e..74489847 100644
--- a/components/webapps/android/webapps_utils.cc
+++ b/components/webapps/browser/android/webapps_utils.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/webapps_utils.h"
+#include "components/webapps/browser/android/webapps_utils.h"
 
 #include <string>
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
-#include "components/webapps/android/webapps_jni_headers/WebappsUtils_jni.h"
+#include "components/webapps/browser/android/webapps_jni_headers/WebappsUtils_jni.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "url/gurl.h"
 
diff --git a/components/webapps/android/webapps_utils.h b/components/webapps/browser/android/webapps_utils.h
similarity index 82%
rename from components/webapps/android/webapps_utils.h
rename to components/webapps/browser/android/webapps_utils.h
index 955d5c8d..9d8019a1 100644
--- a/components/webapps/android/webapps_utils.h
+++ b/components/webapps/browser/android/webapps_utils.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_WEBAPPS_ANDROID_WEBAPPS_UTILS_H_
-#define COMPONENTS_WEBAPPS_ANDROID_WEBAPPS_UTILS_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPPS_UTILS_H_
+#define COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPPS_UTILS_H_
 
 class GURL;
 
@@ -35,4 +35,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_ANDROID_WEBAPPS_UTILS_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_ANDROID_WEBAPPS_UTILS_H_
diff --git a/components/webapps/android/webapps_utils_unittest.cc b/components/webapps/browser/android/webapps_utils_unittest.cc
similarity index 96%
rename from components/webapps/android/webapps_utils_unittest.cc
rename to components/webapps/browser/android/webapps_utils_unittest.cc
index d74f764c0..6414b79 100644
--- a/components/webapps/android/webapps_utils_unittest.cc
+++ b/components/webapps/browser/android/webapps_utils_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/android/webapps_utils.h"
+#include "components/webapps/browser/android/webapps_utils.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/webapps/installable/fake_installable_manager.cc b/components/webapps/browser/installable/fake_installable_manager.cc
similarity index 94%
rename from components/webapps/installable/fake_installable_manager.cc
rename to components/webapps/browser/installable/fake_installable_manager.cc
index 2e48214..95b16a8 100644
--- a/components/webapps/installable/fake_installable_manager.cc
+++ b/components/webapps/browser/installable/fake_installable_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/fake_installable_manager.h"
+#include "components/webapps/browser/installable/fake_installable_manager.h"
 
 #include <utility>
 #include <vector>
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "components/webapps/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_data.h"
 
 namespace webapps {
 
diff --git a/components/webapps/installable/fake_installable_manager.h b/components/webapps/browser/installable/fake_installable_manager.h
similarity index 79%
rename from components/webapps/installable/fake_installable_manager.h
rename to components/webapps/browser/installable/fake_installable_manager.h
index f642d9b..0456c226 100644
--- a/components/webapps/installable/fake_installable_manager.h
+++ b/components/webapps/browser/installable/fake_installable_manager.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_WEBAPPS_INSTALLABLE_FAKE_INSTALLABLE_MANAGER_H_
-#define COMPONENTS_WEBAPPS_INSTALLABLE_FAKE_INSTALLABLE_MANAGER_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_FAKE_INSTALLABLE_MANAGER_H_
+#define COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_FAKE_INSTALLABLE_MANAGER_H_
 
 #include <memory>
 
 #include "base/memory/weak_ptr.h"
-#include "components/webapps/installable/installable_logging.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "url/gurl.h"
 
 namespace blink {
@@ -56,4 +56,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_INSTALLABLE_FAKE_INSTALLABLE_MANAGER_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_FAKE_INSTALLABLE_MANAGER_H_
diff --git a/components/webapps/installable/installable_data.cc b/components/webapps/browser/installable/installable_data.cc
similarity index 95%
rename from components/webapps/installable/installable_data.cc
rename to components/webapps/browser/installable/installable_data.cc
index c205ac04..7325cc9 100644
--- a/components/webapps/installable/installable_data.cc
+++ b/components/webapps/browser/installable/installable_data.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_data.h"
 
 #include <utility>
 
diff --git a/components/webapps/installable/installable_data.h b/components/webapps/browser/installable/installable_data.h
similarity index 92%
rename from components/webapps/installable/installable_data.h
rename to components/webapps/browser/installable/installable_data.h
index d89398f..50f8aef 100644
--- a/components/webapps/installable/installable_data.h
+++ b/components/webapps/browser/installable/installable_data.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_DATA_H_
-#define COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_DATA_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_DATA_H_
+#define COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_DATA_H_
 
 #include <map>
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "components/webapps/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_logging.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "url/gurl.h"
@@ -97,4 +97,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_DATA_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_DATA_H_
diff --git a/components/webapps/installable/installable_logging.cc b/components/webapps/browser/installable/installable_logging.cc
similarity index 98%
rename from components/webapps/installable/installable_logging.cc
rename to components/webapps/browser/installable/installable_logging.cc
index dcd5917..ce0aef4 100644
--- a/components/webapps/installable/installable_logging.cc
+++ b/components/webapps/browser/installable/installable_logging.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_logging.h"
 
 #include <vector>
 
 #include "base/no_destructor.h"
 #include "base/strings/stringprintf.h"
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 
diff --git a/components/webapps/installable/installable_logging.h b/components/webapps/browser/installable/installable_logging.h
similarity index 92%
rename from components/webapps/installable/installable_logging.h
rename to components/webapps/browser/installable/installable_logging.h
index 73b9e97..dbfd2c07 100644
--- a/components/webapps/installable/installable_logging.h
+++ b/components/webapps/browser/installable/installable_logging.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_WEBAPPS_INSTALLABLE_INSTALLABLE_LOGGING_H_
-#define COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_LOGGING_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_LOGGING_H_
+#define COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_LOGGING_H_
 
 #include <string>
 
@@ -79,4 +79,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_LOGGING_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_LOGGING_H_
diff --git a/components/webapps/installable/installable_manager.cc b/components/webapps/browser/installable/installable_manager.cc
similarity index 98%
rename from components/webapps/installable/installable_manager.cc
rename to components/webapps/browser/installable/installable_manager.cc
index 420d2d0..39b6f70 100644
--- a/components/webapps/installable/installable_manager.cc
+++ b/components/webapps/browser/installable/installable_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 
 #include <utility>
 
@@ -14,8 +14,8 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
 #include "components/security_state/core/security_state.h"
-#include "components/webapps/installable/installable_metrics.h"
-#include "components/webapps/webapps_client.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
+#include "components/webapps/browser/webapps_client.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/manifest_icon_downloader.h"
@@ -33,7 +33,7 @@
 #include "url/origin.h"
 
 #if defined(OS_ANDROID)
-#include "components/webapps/android/webapps_icon_utils.h"
+#include "components/webapps/browser/android/webapps_icon_utils.h"
 #endif
 
 namespace webapps {
diff --git a/components/webapps/installable/installable_manager.h b/components/webapps/browser/installable/installable_manager.h
similarity index 95%
rename from components/webapps/installable/installable_manager.h
rename to components/webapps/browser/installable/installable_manager.h
index 97d56750..6f9ef0e 100644
--- a/components/webapps/installable/installable_manager.h
+++ b/components/webapps/browser/installable/installable_manager.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_WEBAPPS_INSTALLABLE_INSTALLABLE_MANAGER_H_
-#define COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_MANAGER_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_MANAGER_H_
+#define COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_MANAGER_H_
 
 #include <map>
 #include <memory>
@@ -16,10 +16,10 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "components/webapps/installable/installable_data.h"
-#include "components/webapps/installable/installable_logging.h"
-#include "components/webapps/installable/installable_params.h"
-#include "components/webapps/installable/installable_task_queue.h"
+#include "components/webapps/browser/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_logging.h"
+#include "components/webapps/browser/installable/installable_params.h"
+#include "components/webapps/browser/installable/installable_task_queue.h"
 #include "content/public/browser/installability_error.h"
 #include "content/public/browser/service_worker_context.h"
 #include "content/public/browser/service_worker_context_observer.h"
@@ -279,4 +279,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_MANAGER_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_MANAGER_H_
diff --git a/components/webapps/installable/installable_manager_unittest.cc b/components/webapps/browser/installable/installable_manager_unittest.cc
similarity index 99%
rename from components/webapps/installable/installable_manager_unittest.cc
rename to components/webapps/browser/installable/installable_manager_unittest.cc
index 437025f9..49aaae0f 100644
--- a/components/webapps/installable/installable_manager_unittest.cc
+++ b/components/webapps/browser/installable/installable_manager_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 
 #include "base/feature_list.h"
 #include "base/optional.h"
diff --git a/components/webapps/installable/installable_metrics.cc b/components/webapps/browser/installable/installable_metrics.cc
similarity index 96%
rename from components/webapps/installable/installable_metrics.cc
rename to components/webapps/browser/installable/installable_metrics.cc
index 686f96d..ca7f7082 100644
--- a/components/webapps/installable/installable_metrics.cc
+++ b/components/webapps/browser/installable/installable_metrics.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_metrics.h"
+#include "components/webapps/browser/installable/installable_metrics.h"
 
 #include "base/metrics/histogram_macros.h"
 #include "base/notreached.h"
 #include "build/build_config.h"
-#include "components/webapps/webapps_client.h"
+#include "components/webapps/browser/webapps_client.h"
 #include "content/public/browser/web_contents.h"
 
 namespace webapps {
diff --git a/components/webapps/installable/installable_metrics.h b/components/webapps/browser/installable/installable_metrics.h
similarity index 95%
rename from components/webapps/installable/installable_metrics.h
rename to components/webapps/browser/installable/installable_metrics.h
index f2d3dc0..b25cff6 100644
--- a/components/webapps/installable/installable_metrics.h
+++ b/components/webapps/browser/installable/installable_metrics.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_WEBAPPS_INSTALLABLE_INSTALLABLE_METRICS_H_
-#define COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_METRICS_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_METRICS_H_
+#define COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_METRICS_H_
 
 #include "base/macros.h"
 #include "base/time/time.h"
@@ -142,4 +142,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_METRICS_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_METRICS_H_
diff --git a/components/webapps/installable/installable_params.cc b/components/webapps/browser/installable/installable_params.cc
similarity index 84%
rename from components/webapps/installable/installable_params.cc
rename to components/webapps/browser/installable/installable_params.cc
index 07dca90a..90a64364 100644
--- a/components/webapps/installable/installable_params.cc
+++ b/components/webapps/browser/installable/installable_params.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_params.h"
+#include "components/webapps/browser/installable/installable_params.h"
 
 namespace webapps {
 
diff --git a/components/webapps/installable/installable_params.h b/components/webapps/browser/installable/installable_params.h
similarity index 91%
rename from components/webapps/installable/installable_params.h
rename to components/webapps/browser/installable/installable_params.h
index fb415c3f..dee8aea 100644
--- a/components/webapps/installable/installable_params.h
+++ b/components/webapps/browser/installable/installable_params.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_WEBAPPS_INSTALLABLE_INSTALLABLE_PARAMS_H_
-#define COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_PARAMS_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_PARAMS_H_
+#define COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_PARAMS_H_
 
 namespace webapps {
 
@@ -64,4 +64,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_PARAMS_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_PARAMS_H_
diff --git a/components/webapps/installable/installable_task_queue.cc b/components/webapps/browser/installable/installable_task_queue.cc
similarity index 96%
rename from components/webapps/installable/installable_task_queue.cc
rename to components/webapps/browser/installable/installable_task_queue.cc
index 6bc9922..2e78e046 100644
--- a/components/webapps/installable/installable_task_queue.cc
+++ b/components/webapps/browser/installable/installable_task_queue.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_task_queue.h"
+#include "components/webapps/browser/installable/installable_task_queue.h"
 
 #include <map>
 #include <utility>
diff --git a/components/webapps/installable/installable_task_queue.h b/components/webapps/browser/installable/installable_task_queue.h
similarity index 86%
rename from components/webapps/installable/installable_task_queue.h
rename to components/webapps/browser/installable/installable_task_queue.h
index 7578f42..95c49872 100644
--- a/components/webapps/installable/installable_task_queue.h
+++ b/components/webapps/browser/installable/installable_task_queue.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
-#define COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
+#define COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
 
 #include <deque>
 
 #include "base/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "components/webapps/installable/installable_data.h"
-#include "components/webapps/installable/installable_params.h"
+#include "components/webapps/browser/installable/installable_data.h"
+#include "components/webapps/browser/installable/installable_params.h"
 
 namespace webapps {
 
@@ -84,4 +84,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_INSTALLABLE_INSTALLABLE_TASK_QUEUE_H_
diff --git a/components/webapps/installable/installable_task_queue_unittest.cc b/components/webapps/browser/installable/installable_task_queue_unittest.cc
similarity index 95%
rename from components/webapps/installable/installable_task_queue_unittest.cc
rename to components/webapps/browser/installable/installable_task_queue_unittest.cc
index e4fa0287..19e56aa 100644
--- a/components/webapps/installable/installable_task_queue_unittest.cc
+++ b/components/webapps/browser/installable/installable_task_queue_unittest.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/installable/installable_task_queue.h"
+#include "components/webapps/browser/installable/installable_task_queue.h"
 
-#include "components/webapps/installable/installable_manager.h"
+#include "components/webapps/browser/installable/installable_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace webapps {
diff --git a/components/webapps/webapps_client.cc b/components/webapps/browser/webapps_client.cc
similarity index 89%
rename from components/webapps/webapps_client.cc
rename to components/webapps/browser/webapps_client.cc
index bec30db..d76eb20 100644
--- a/components/webapps/webapps_client.cc
+++ b/components/webapps/browser/webapps_client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/webapps/webapps_client.h"
+#include "components/webapps/browser/webapps_client.h"
 
 namespace webapps {
 
diff --git a/components/webapps/webapps_client.h b/components/webapps/browser/webapps_client.h
similarity index 91%
rename from components/webapps/webapps_client.h
rename to components/webapps/browser/webapps_client.h
index fef3303..6772112c 100644
--- a/components/webapps/webapps_client.h
+++ b/components/webapps/browser/webapps_client.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_WEBAPPS_WEBAPPS_CLIENT_H_
-#define COMPONENTS_WEBAPPS_WEBAPPS_CLIENT_H_
+#ifndef COMPONENTS_WEBAPPS_BROWSER_WEBAPPS_CLIENT_H_
+#define COMPONENTS_WEBAPPS_BROWSER_WEBAPPS_CLIENT_H_
 
 #include "build/build_config.h"
 #include "components/security_state/core/security_state.h"
@@ -62,4 +62,4 @@
 
 }  // namespace webapps
 
-#endif  // COMPONENTS_WEBAPPS_WEBAPPS_CLIENT_H_
+#endif  // COMPONENTS_WEBAPPS_BROWSER_WEBAPPS_CLIENT_H_
diff --git a/content/browser/conversions/conversion_policy.cc b/content/browser/conversions/conversion_policy.cc
index 4df9ed7..59aecba 100644
--- a/content/browser/conversions/conversion_policy.cc
+++ b/content/browser/conversions/conversion_policy.cc
@@ -7,7 +7,7 @@
 #include "base/format_macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/rand_util.h"
-#include "base/strings/stringprintf.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 
 namespace content {
@@ -59,18 +59,14 @@
   if (noise_provider_)
     conversion_data = noise_provider_->GetNoisedConversionData(conversion_data);
 
-  // Allow at most 3 bits of entropy in conversion data. base::StringPrintf() is
-  // used over base::HexEncode() because HexEncode() returns a hex string with
-  // little-endian ordering. Big-endian ordering is expected here because the
-  // API assumes big-endian when parsing attributes.
-  return base::StringPrintf("%" PRIx64,
-                            conversion_data % kMaxAllowedConversionValues);
+  // Allow at most 3 bits of entropy in conversion data.
+  return base::NumberToString(conversion_data % kMaxAllowedConversionValues);
 }
 
 std::string ConversionPolicy::GetSanitizedImpressionData(
     uint64_t impression_data) const {
   // Impression data is allowed the full 64 bits.
-  return base::StringPrintf("%" PRIx64, impression_data);
+  return base::NumberToString(impression_data);
 }
 
 base::Time ConversionPolicy::GetExpiryTimeForImpression(
diff --git a/content/browser/conversions/conversion_policy.h b/content/browser/conversions/conversion_policy.h
index 79f86a7..c7c2f62 100644
--- a/content/browser/conversions/conversion_policy.h
+++ b/content/browser/conversions/conversion_policy.h
@@ -49,7 +49,7 @@
       uint64_t conversion_data) const;
 
   // Gets the sanitized impression data for an impression. Returns the decoded
-  // number as a hexadecimal string.
+  // number as a base 10 string.
   virtual std::string GetSanitizedImpressionData(
       uint64_t impression_data) const;
 
diff --git a/content/browser/conversions/conversion_policy_unittest.cc b/content/browser/conversions/conversion_policy_unittest.cc
index 15ff3505..27625ff 100644
--- a/content/browser/conversions/conversion_policy_unittest.cc
+++ b/content/browser/conversions/conversion_policy_unittest.cc
@@ -51,9 +51,9 @@
 TEST_F(ConversionPolicyTest, SanitizeHighEntropyImpressionData_Unchanged) {
   uint64_t impression_data = 256LU;
 
-  // The policy should not alter the impression data, and return the hexadecimal
+  // The policy should not alter the impression data, and return the base 10
   // representation.
-  EXPECT_EQ("100",
+  EXPECT_EQ("256",
             ConversionPolicy().GetSanitizedImpressionData(impression_data));
 }
 
diff --git a/content/browser/conversions/conversion_storage_sql.cc b/content/browser/conversions/conversion_storage_sql.cc
index cfae07d..985a55d 100644
--- a/content/browser/conversions/conversion_storage_sql.cc
+++ b/content/browser/conversions/conversion_storage_sql.cc
@@ -685,6 +685,9 @@
 
 bool ConversionStorageSql::InitializeSchema() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // TODO(https://crbug.com/1163599): Convert impression data and conversion
+  // data fields to integers.
+  //
   // TODO(johnidel, csharrison): Many impressions will share a target origin and
   // a reporting origin, so it makes sense to make a "shared string" table for
   // these to save disk / memory. However, this complicates the schema a lot, so
diff --git a/content/browser/conversions/impression_declaration_browsertest.cc b/content/browser/conversions/impression_declaration_browsertest.cc
index ca25e8f..6d7c485 100644
--- a/content/browser/conversions/impression_declaration_browsertest.cc
+++ b/content/browser/conversions/impression_declaration_browsertest.cc
@@ -245,12 +245,12 @@
       web_contents(),
       https_server()->GetURL("b.test", "/page_with_impression_creator.html")));
 
-  // The provided data overflows an unsigned 64 bit int, and should be handled
+  // The provided data underflows an unsigned 64 bit int, and should be handled
   // properly.
   EXPECT_TRUE(ExecJs(web_contents(), R"(
     createImpressionTag("link",
                         "page_with_conversion_redirect.html",
-                        "FFFFFFFFFFFFFFFFFFFFFF" /* impression data */,
+                        "-1" /* impression data */,
                         "https://a.com" /* conversion_destination */);)"));
   EXPECT_TRUE(ExecJs(shell(), "simulateClick(\'link\');"));
 
@@ -476,7 +476,7 @@
   content::UntrustworthyContextMenuParams params =
       context_menu_filter->get_params();
   EXPECT_TRUE(params.impression);
-  EXPECT_EQ(16UL, params.impression->impression_data);
+  EXPECT_EQ(10UL, params.impression->impression_data);
   EXPECT_EQ(url::Origin::Create(GURL("https://dest.com")),
             params.impression->conversion_destination);
 }
diff --git a/content/browser/form_controls_browsertest.cc b/content/browser/form_controls_browsertest.cc
index 609b954..6b293446 100644
--- a/content/browser/form_controls_browsertest.cc
+++ b/content/browser/form_controls_browsertest.cc
@@ -101,7 +101,7 @@
     // - Slight differences in radio and checkbox rendering in 10.15
     cc::FuzzyPixelComparator comparator(
         /* discard_alpha */ true,
-        /* error_pixels_percentage_limit */ 9.f,
+        /* error_pixels_percentage_limit */ 11.f,
         /* small_error_pixels_percentage_limit */ 0.f,
         /* avg_abs_error_limit */ 20.f,
         /* max_abs_error_limit */ 79.f,
@@ -158,6 +158,25 @@
           /* screenshot_height */ 40);
 }
 
+IN_PROC_BROWSER_TEST_F(FormControlsBrowserTest, Input) {
+  RunTest("form_controls_browsertest_input",
+          "<!-- text inputs -->"
+          "<style>input {width: 150px;}</style>"
+          "<input type=\"text\" /><br><br>"
+          "<input type=\"number\" /><br><br>"
+          "<input type=\"search\" /><br><br>"
+          "<input type=\"email\" /><br><br>"
+          "<input type=\"password\" /><br><br>"
+          "<!-- border -->"
+          "<input type=\"text\" style=\"border: 3px solid lime;\"/><br><br>"
+          "<!-- shadow -->"
+          "<input type=\"text\" style=\"box-shadow: 4px 4px 10px rgba(255,0,0,0.5), inset 4px 4px 4px rgba(0,255,0,0.5);\"/><br><br>"
+          "<!-- disabled -->"
+          "<input type=\"text\" disabled/>",
+          /* screenshot_width */ 200,
+          /* screenshot_height */ 330);
+}
+
 // TODO(jarhar): Add tests for other elements from
 //   https://concrete-hardboard.glitch.me
 
diff --git a/content/browser/renderer_host/ancestor_throttle.cc b/content/browser/renderer_host/ancestor_throttle.cc
index e08419c..db722e2 100644
--- a/content/browser/renderer_host/ancestor_throttle.cc
+++ b/content/browser/renderer_host/ancestor_throttle.cc
@@ -23,10 +23,12 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "net/http/http_response_headers.h"
 #include "services/network/public/cpp/content_security_policy/csp_context.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom.h"
 
 namespace content {
 
@@ -453,15 +455,11 @@
 
 AncestorThrottle::CheckResult AncestorThrottle::EvaluateEmbeddingOptIn(
     LoggingDisposition logging) {
-  if (!base::FeatureList::IsEnabled(features::kEmbeddingRequiresOptIn))
-    return CheckResult::PROCEED;
-
+  // If the proposal in https://github.com/mikewest/embedding-requires-opt-in is
+  // enabled, a response will be blocked unless it's explicitly opted-into
+  // being embeddable via 'X-Frame-Options'/'frame-ancestors', or is same-origin
+  // with its ancestors.
   NavigationRequest* request = NavigationRequest::From(navigation_handle());
-
-  // If embedding requires opt-in, then we check whether the response opted-into
-  // embedding via either an 'X-Frame-Options' header or a 'frame-ancestors'
-  // directive. If neither is present, the response will be blocked unless it is
-  // same-origin with its ancestor chain.
   if (request->response()->parsed_headers->xfo ==
           network::mojom::XFrameOptionsValue::kNone &&
       !HeadersContainFrameAncestorsCSP(request->response()->parsed_headers)) {
@@ -471,8 +469,16 @@
         url::Origin::Create(navigation_handle()->GetURL());
     while (parent) {
       if (!parent->GetLastCommittedOrigin().IsSameOriginWith(current_origin)) {
+        GetContentClient()->browser()->LogWebFeatureForCurrentPage(
+            parent, blink::mojom::WebFeature::
+                        kEmbeddedCrossOriginFrameWithoutFrameAncestorsOrXFO);
+
+        if (!base::FeatureList::IsEnabled(features::kEmbeddingRequiresOptIn))
+          return CheckResult::PROCEED;
+
         if (logging == LoggingDisposition::LOG_TO_CONSOLE)
           ConsoleErrorEmbeddingRequiresOptIn();
+
         return CheckResult::BLOCK;
       }
       parent = ParentOrOuterDelegate(parent);
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index 66933a96..548457e 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -1102,7 +1102,7 @@
   // If this is a navigation to a matching pending_entry_ and the SiteInstance
   // has changed, this must be treated as a new navigation with replacement.
   // Set the replacement bit here and ClassifyNavigation will identify this
-  // case and return NEW_PAGE.
+  // case and return NEW_ENTRY.
   if (!rfh->GetParent() && pending_entry_ &&
       pending_entry_->GetUniqueID() ==
           navigation_request->commit_params().nav_entry_id &&
@@ -1132,24 +1132,24 @@
   // other navigation types. See https://crbug.com/900036.
   // TODO(crbug.com/926009): Handle history.pushState() as well.
   bool keep_pending_entry = is_same_document_navigation &&
-                            details->type == NAVIGATION_TYPE_EXISTING_PAGE &&
+                            details->type == NAVIGATION_TYPE_EXISTING_ENTRY &&
                             pending_entry_ &&
                             !PendingEntryMatchesRequest(navigation_request);
 
   switch (details->type) {
-    case NAVIGATION_TYPE_NEW_PAGE:
-      RendererDidNavigateToNewPage(
+    case NAVIGATION_TYPE_NEW_ENTRY:
+      RendererDidNavigateToNewEntry(
           rfh, params, details->is_same_document, details->did_replace_entry,
           previous_document_was_activated, navigation_request);
       break;
-    case NAVIGATION_TYPE_EXISTING_PAGE:
-      RendererDidNavigateToExistingPage(rfh, params, details->is_same_document,
-                                        was_restored, navigation_request,
-                                        keep_pending_entry);
+    case NAVIGATION_TYPE_EXISTING_ENTRY:
+      RendererDidNavigateToExistingEntry(rfh, params, details->is_same_document,
+                                         was_restored, navigation_request,
+                                         keep_pending_entry);
       break;
-    case NAVIGATION_TYPE_SAME_PAGE:
-      RendererDidNavigateToSamePage(rfh, params, details->is_same_document,
-                                    navigation_request);
+    case NAVIGATION_TYPE_SAME_ENTRY:
+      RendererDidNavigateToSameEntry(rfh, params, details->is_same_document,
+                                     navigation_request);
       break;
     case NAVIGATION_TYPE_NEW_SUBFRAME:
       RendererDidNavigateNewSubframe(
@@ -1284,11 +1284,11 @@
       "ClassifyNavigation");
 
   if (params.did_create_new_entry) {
-    // A new entry. We may or may not have a pending entry for the page, and
+    // A new entry. We may or may not have a corresponding pending entry, and
     // this may or may not be the main frame.
     if (!rfh->GetParent()) {
-      trace_return.set_return_reason("new entry, no parent, new page");
-      return NAVIGATION_TYPE_NEW_PAGE;
+      trace_return.set_return_reason("new entry, no parent, new entry");
+      return NAVIGATION_TYPE_NEW_ENTRY;
     }
 
     // When this is a new subframe navigation, we should have a committed page
@@ -1306,7 +1306,7 @@
     return NAVIGATION_TYPE_NEW_SUBFRAME;
   }
 
-  // We only clear the session history when navigating to a new page.
+  // We only clear the session history in tests when navigating to a new entry.
   DCHECK(!params.history_list_was_cleared);
 
   if (rfh->GetParent()) {
@@ -1340,11 +1340,11 @@
     // This is history.replaceState() or history.reload().
     // TODO(nasko): With error page isolation, reloading an existing session
     // history entry can result in change of SiteInstance. Check for such a case
-    // here and classify it as NEW_PAGE, as such navigations should be treated
+    // here and classify it as NEW_ENTRY, as such navigations should be treated
     // as new with replacement.
     trace_return.set_return_reason(
-        "nav entry 0, last committed, existing page");
-    return NAVIGATION_TYPE_EXISTING_PAGE;
+        "nav entry 0, last committed, existing entry");
+    return NAVIGATION_TYPE_EXISTING_ENTRY;
   }
 
   if (pending_entry_ && pending_entry_->GetUniqueID() == nav_entry_id) {
@@ -1355,8 +1355,8 @@
     // reloaded into a different SiteInstance.
     if (pending_entry_->site_instance() &&
         pending_entry_->site_instance() != rfh->GetSiteInstance()) {
-      trace_return.set_return_reason("pending matching nav entry, new page");
-      return NAVIGATION_TYPE_NEW_PAGE;
+      trace_return.set_return_reason("pending matching nav entry, new entry");
+      return NAVIGATION_TYPE_NEW_ENTRY;
     }
 
     if (pending_entry_index_ == -1) {
@@ -1367,8 +1367,8 @@
       // we must treat it as NEW since the SiteInstance doesn't match the entry.
       if (!GetLastCommittedEntry() ||
           GetLastCommittedEntry()->site_instance() != rfh->GetSiteInstance()) {
-        trace_return.set_return_reason("no pending, new page");
-        return NAVIGATION_TYPE_NEW_PAGE;
+        trace_return.set_return_reason("no pending, new entry");
+        return NAVIGATION_TYPE_NEW_ENTRY;
       }
 
       // Otherwise, this happens when you press enter in the URL bar to reload.
@@ -1377,56 +1377,56 @@
       // doesn't want to have a new back/forward entry when they do this).
       // Therefore we want to just ignore the pending entry and go back to where
       // we were (the "existing entry").
-      // TODO(creis,avi): Eliminate SAME_PAGE in https://crbug.com/536102.
-      trace_return.set_return_reason("no pending, same page");
-      return NAVIGATION_TYPE_SAME_PAGE;
+      // TODO(creis,avi): Eliminate SAME_ENTRY in https://crbug.com/536102.
+      trace_return.set_return_reason("no pending, same entry");
+      return NAVIGATION_TYPE_SAME_ENTRY;
     }
   }
 
   // Everything below here is assumed to be an existing entry, but if there is
   // no last committed entry, we must consider it a new navigation instead.
   if (!GetLastCommittedEntry()) {
-    trace_return.set_return_reason("no last committed, new page");
-    return NAVIGATION_TYPE_NEW_PAGE;
+    trace_return.set_return_reason("no last committed, new entry");
+    return NAVIGATION_TYPE_NEW_ENTRY;
   }
 
   if (params.intended_as_new_entry) {
     // This was intended to be a navigation to a new entry but the pending entry
-    // got cleared in the meanwhile. Classify as EXISTING_PAGE because we may or
-    // may not have a pending entry.
-    trace_return.set_return_reason("indented as new entry, new page");
-    return NAVIGATION_TYPE_EXISTING_PAGE;
+    // got cleared in the meanwhile. Classify as EXISTING_ENTRY because we may
+    // or may not have a pending entry.
+    trace_return.set_return_reason("indented as new entry, existing entry");
+    return NAVIGATION_TYPE_EXISTING_ENTRY;
   }
 
   if (params.url_is_unreachable && failed_pending_entry_id_ != 0 &&
       nav_entry_id == failed_pending_entry_id_) {
     // If the renderer was going to a new pending entry that got cleared because
     // of an error, this is the case of the user trying to retry a failed load
-    // by pressing return. Classify as EXISTING_PAGE because we probably don't
+    // by pressing return. Classify as EXISTING_ENTRY because we probably don't
     // have a pending entry.
     trace_return.set_return_reason(
-        "unreachable, matching pending, existing page");
-    return NAVIGATION_TYPE_EXISTING_PAGE;
+        "unreachable, matching pending, existing entry");
+    return NAVIGATION_TYPE_EXISTING_ENTRY;
   }
 
-  // Now we know that the notification is for an existing page. Find that entry.
+  // Now we know that the notification is for an existing entry; find it.
   int existing_entry_index = GetEntryIndexWithUniqueID(nav_entry_id);
   trace_return.traced_value()->SetInteger("existing_entry_index",
                                           existing_entry_index);
   if (existing_entry_index == -1) {
     // The renderer has committed a navigation to an entry that no longer
     // exists. Because the renderer is showing that page, resurrect that entry.
-    trace_return.set_return_reason("existing entry -1, new page");
-    return NAVIGATION_TYPE_NEW_PAGE;
+    trace_return.set_return_reason("existing entry -1, new entry");
+    return NAVIGATION_TYPE_NEW_ENTRY;
   }
 
   // Since we weeded out "new" navigations above, we know this is an existing
   // (back/forward) navigation.
-  trace_return.set_return_reason("default return, existing page");
-  return NAVIGATION_TYPE_EXISTING_PAGE;
+  trace_return.set_return_reason("default return, existing entry");
+  return NAVIGATION_TYPE_EXISTING_ENTRY;
 }
 
-void NavigationControllerImpl::RendererDidNavigateToNewPage(
+void NavigationControllerImpl::RendererDidNavigateToNewEntry(
     RenderFrameHostImpl* rfh,
     const mojom::DidCommitProvisionalLoadParams& params,
     bool is_same_document,
@@ -1486,8 +1486,8 @@
     }
   }
 
-  // Only make a copy of the pending entry if it is appropriate for the new page
-  // that was just loaded. Verify this by checking if the entry corresponds
+  // Only make a copy of the pending entry if it is appropriate for the new
+  // document that just loaded. Verify this by checking if the entry corresponds
   // to the given NavigationRequest. Additionally, coarsely check that:
   // 1. The SiteInstance hasn't been assigned to something else.
   // 2. The pending entry was intended as a new entry, rather than being a
@@ -1513,7 +1513,8 @@
     }
   }
 
-  // For non-in-page commits with no matching pending entry, create a new entry.
+  // For cross-document commits with no matching pending entry, create a new
+  // entry.
   if (!new_entry) {
     new_entry = std::make_unique<NavigationEntryImpl>(
         rfh->GetSiteInstance(), params.url, Referrer(*params.referrer),
@@ -1531,7 +1532,7 @@
         &url, browser_context_, &needs_update);
     new_entry->set_update_virtual_url_with_url(needs_update);
 
-    // When navigating to a new page, give the browser URL handler a chance to
+    // When navigating to a new entry, give the browser URL handler a chance to
     // update the virtual URL based on the new URL. For example, this is needed
     // to show chrome://bookmarks/#1 when the bookmarks webui extension changes
     // the URL.
@@ -1624,7 +1625,7 @@
                        !request->post_commit_error_page_html().empty());
 }
 
-void NavigationControllerImpl::RendererDidNavigateToExistingPage(
+void NavigationControllerImpl::RendererDidNavigateToExistingEntry(
     RenderFrameHostImpl* rfh,
     const mojom::DidCommitProvisionalLoadParams& params,
     bool is_same_document,
@@ -1640,8 +1641,8 @@
   NavigationEntryImpl* entry;
   if (params.intended_as_new_entry) {
     // This was intended as a new entry but the pending entry was lost in the
-    // meanwhile and no new page was created. We are stuck at the last committed
-    // entry.
+    // meanwhile and no new entry was created. We are stuck at the last
+    // committed entry.
     entry = GetLastCommittedEntry();
     // If this is a same document navigation, then there's no SSLStatus in the
     // NavigationRequest so don't overwrite the existing entry's SSLStatus.
@@ -1718,7 +1719,7 @@
     }
   } else {
     // This is renderer-initiated. The only kinds of renderer-initated
-    // navigations that are EXISTING_PAGE are reloads and history.replaceState,
+    // navigations that are EXISTING_ENTRY are reloads and history.replaceState,
     // which land us at the last committed entry.
     entry = GetLastCommittedEntry();
 
@@ -1804,7 +1805,7 @@
   last_committed_entry_index_ = GetIndexOfEntry(entry);
 }
 
-void NavigationControllerImpl::RendererDidNavigateToSamePage(
+void NavigationControllerImpl::RendererDidNavigateToSameEntry(
     RenderFrameHostImpl* rfh,
     const mojom::DidCommitProvisionalLoadParams& params,
     bool is_same_document,
@@ -1832,8 +1833,8 @@
   existing_entry->SetURL(params.url);
 
   // If a user presses enter in the omnibox and the server redirects, the URL
-  // might change (but it's still considered a SAME_PAGE navigation), so we must
-  // update the SSL status if we perform a network request (e.g. a
+  // might change (but it's still considered a SAME_ENTRY navigation), so we
+  // must update the SSL status if we perform a network request (e.g. a
   // non-same-document navigation). Requests that don't result in a network
   // request do not have a valid SSL status, but since the document didn't
   // change, the previous SSLStatus is still valid.
@@ -3258,8 +3259,8 @@
         params.redirect_chain, blink::PageState(), "GET", -1,
         blob_url_loader_factory, nullptr /* web_bundle_navigation_info */,
         // If in NavigateWithoutEntry we later determine that this navigation is
-        // a SAME_PAGE conversion of a new navigation into a reload, we will set
-        // the right document policies there.
+        // a SAME_ENTRY conversion of a new navigation into a reload, we will
+        // set the right document policies there.
         nullptr /* document_policies */);
   } else {
     // Otherwise, create a pending entry for the main frame.
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index f358271..3c276e09 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -498,26 +498,26 @@
   // anything if some random subframe is loaded. It will return true if anything
   // changed, or false if not.
   //
-  // The NewPage and NewSubframe functions take in |replace_entry| to pass to
+  // The NewEntry and NewSubframe functions take in |replace_entry| to pass to
   // InsertOrReplaceEntry, in case the newly created NavigationEntry is meant to
   // replace the current one (e.g., for location.replace or successful loads
   // after net errors), in contrast to updating a NavigationEntry in place
   // (e.g., for history.replaceState).
-  void RendererDidNavigateToNewPage(
+  void RendererDidNavigateToNewEntry(
       RenderFrameHostImpl* rfh,
       const mojom::DidCommitProvisionalLoadParams& params,
       bool is_same_document,
       bool replace_entry,
       bool previous_document_was_activated,
       NavigationRequest* request);
-  void RendererDidNavigateToExistingPage(
+  void RendererDidNavigateToExistingEntry(
       RenderFrameHostImpl* rfh,
       const mojom::DidCommitProvisionalLoadParams& params,
       bool is_same_document,
       bool was_restored,
       NavigationRequest* request,
       bool keep_pending_entry);
-  void RendererDidNavigateToSamePage(
+  void RendererDidNavigateToSameEntry(
       RenderFrameHostImpl* rfh,
       const mojom::DidCommitProvisionalLoadParams& params,
       bool is_same_document,
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index 3ceda6db..7db6b46f 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -1518,25 +1518,25 @@
                             ->root();
 
   // Navigate to a page that fails to load. It must result in an error page, the
-  // NEW_PAGE navigation type, and an addition to the history list.
+  // NEW_ENTRY navigation type, and an addition to the history list.
   {
     FrameNavigateParamsCapturer capturer(root);
     NavigateFrameToURL(root, error_url);
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     NavigationEntry* entry = controller.GetLastCommittedEntry();
     EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
     EXPECT_EQ(2, controller.GetEntryCount());
   }
 
   // Navigate again to the page that fails to load. It results in an error page,
-  // the NEW_PAGE navigation type with replacement, and no addition to the
+  // the NEW_ENTRY navigation type with replacement, and no addition to the
   // history list.
   {
     FrameNavigateParamsCapturer capturer(root);
     NavigateFrameToURL(root, error_url);
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.did_replace_entry());
     NavigationEntry* entry = controller.GetLastCommittedEntry();
     EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
@@ -1552,7 +1552,7 @@
     FrameNavigateParamsCapturer capturer(root);
     RendererLocationReplace(shell(), error_url);
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.did_replace_entry());
     NavigationEntry* entry = controller.GetLastCommittedEntry();
     EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
@@ -1565,13 +1565,13 @@
   EXPECT_TRUE(NavigateToURL(shell(), web_ui_page));
   EXPECT_EQ(4, controller.GetEntryCount());
 
-  // ... and replace it with a failed load. (It is NEW_PAGE for the reason noted
-  // above.)
+  // ... and replace it with a failed load. (It is NEW_ENTRY for the reason
+  // noted above.)
   {
     FrameNavigateParamsCapturer capturer(root);
     RendererLocationReplace(shell(), error_url);
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.did_replace_entry());
     NavigationEntry* entry = controller.GetLastCommittedEntry();
     EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
@@ -1582,10 +1582,10 @@
 // Various tests for navigation type classifications. TODO(avi): It's rather
 // bogus that the same info is in two different enums; http://crbug.com/453555.
 
-// Verify that navigations for NAVIGATION_TYPE_NEW_PAGE are correctly
+// Verify that navigations for NAVIGATION_TYPE_NEW_ENTRY are correctly
 // classified.
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       NavigationTypeClassification_NewPage) {
+                       NavigationTypeClassification_NewEntry) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
 
   FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
@@ -1603,7 +1603,7 @@
     // transition? Lots of these transitions should be cleaned up.
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_LINK));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1615,7 +1615,7 @@
     capturer.Wait();
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_LINK));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -1627,7 +1627,7 @@
     capturer.Wait();
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_LINK));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1643,7 +1643,7 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1658,7 +1658,7 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -1673,15 +1673,15 @@
       capturer.transition(),
       ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                 ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-  EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+  EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
   EXPECT_TRUE(capturer.did_replace_entry());
   EXPECT_FALSE(capturer.is_same_document());
 }
 
-// Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
+// Verify that navigations for NAVIGATION_TYPE_EXISTING_ENTRY are correctly
 // classified.
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       NavigationTypeClassification_ExistingPage) {
+                       NavigationTypeClassification_ExistingEntry) {
   GURL url1(embedded_test_server()->GetURL(
       "/navigation_controller/simple_page_1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), url1));
@@ -1703,7 +1703,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FORWARD_BACK |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1717,7 +1717,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FORWARD_BACK |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1731,7 +1731,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FORWARD_BACK |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1745,7 +1745,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FORWARD_BACK |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1759,7 +1759,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FORWARD_BACK |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1773,7 +1773,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FORWARD_BACK |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1784,7 +1784,7 @@
     capturer.Wait();
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_RELOAD));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1797,7 +1797,7 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -1813,7 +1813,7 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.did_replace_entry());
     EXPECT_FALSE(capturer.is_same_document());
   }
@@ -1830,7 +1830,7 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.did_replace_entry());
     EXPECT_TRUE(capturer.is_same_document());
   }
@@ -1846,7 +1846,7 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -1869,7 +1869,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FORWARD_BACK |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -1882,7 +1882,7 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_FORWARD_BACK)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -1903,7 +1903,7 @@
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
                                   ui::PAGE_TRANSITION_FORWARD_BACK |
                                   ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -1916,15 +1916,15 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_FORWARD_BACK)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 }
 
-// Verify that navigations for NAVIGATION_TYPE_SAME_PAGE are correctly
+// Verify that navigations for NAVIGATION_TYPE_SAME_ENTRY are correctly
 // classified.
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       NavigationTypeClassification_SamePage) {
+                       NavigationTypeClassification_SameEntry) {
   GURL url1(embedded_test_server()->GetURL(
       "/navigation_controller/simple_page_1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), url1));
@@ -1942,7 +1942,7 @@
     capturer.Wait();
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_LINK));
-    EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_SAME_ENTRY, capturer.navigation_type());
   }
 }
 
@@ -2026,7 +2026,7 @@
   EXPECT_FLOAT_EQ(expected_window_scroll_y, window_scroll_y);
 }
 
-// Verify that empty GURL navigations are not classified as SAME_PAGE.
+// Verify that empty GURL navigations are not classified as SAME_ENTRY.
 // See https://crbug.com/534980.
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
                        NavigationTypeClassification_EmptyGURL) {
@@ -2040,13 +2040,13 @@
 
   {
     // Load an (invalid) empty GURL.  Blink will treat this as an inert commit,
-    // but we don't want it to show up as SAME_PAGE.
+    // but we don't want it to show up as SAME_ENTRY.
     FrameNavigateParamsCapturer capturer(root);
     NavigateFrameToURL(root, GURL());
     capturer.Wait();
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_LINK));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
   }
 }
 
@@ -2225,12 +2225,12 @@
     ASSERT_EQ(2U, capturer.navigation_types().size());
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transitions()[0], ui::PAGE_TRANSITION_LINK));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_types()[0]);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_types()[0]);
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transitions()[1],
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_types()[1]);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_types()[1]);
     EXPECT_TRUE(capturer.did_replace_entries()[1]);
   }
 }
@@ -2256,7 +2256,7 @@
     capturer.Wait();
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_LINK));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -2268,7 +2268,7 @@
     capturer.Wait();
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_LINK));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -2585,7 +2585,7 @@
     std::string script = "history.pushState({}, '', 'pushed')";
     EXPECT_TRUE(ExecJs(root, script));
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -2631,7 +2631,7 @@
     std::string script = "history.replaceState({}, '', 'replaced')";
     EXPECT_TRUE(ExecJs(root, script));
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -2704,7 +2704,7 @@
     std::string script = "history.pushState({}, 'foo', 'foo')";
     EXPECT_TRUE(ExecJs(root, script));
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -2762,7 +2762,7 @@
     std::string script = "history.pushState({}, 'foo', 'foo')";
     EXPECT_TRUE(ExecJs(root, script));
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -5366,7 +5366,7 @@
     capturer.Wait();
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_RELOAD));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
@@ -5667,7 +5667,7 @@
 
     // The fact that there was a pending entry shouldn't interfere with the
     // classification.
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 }
@@ -5753,7 +5753,7 @@
     std::string script = "history.pushState({}, '', 'pushed')";
     EXPECT_TRUE(ExecJs(root, script));
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.is_same_document());
   }
 
@@ -6084,7 +6084,7 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(capturer.did_replace_entry());
   }
 
@@ -7493,7 +7493,7 @@
   EXPECT_EQ(0U, root->child_count());
 }
 
-// Test that navigations classified as SAME_PAGE properly update all the
+// Test that navigations classified as SAME_ENTRY properly update all the
 // members of FrameNavigationEntry. If not, it is possible to get a mismatch
 // between the origin and URL of a document as seen in
 // https://crbug.com/630103.
@@ -7534,7 +7534,7 @@
   }
 
   // Prior to fixing the issue, the above omnibox navigation (which is
-  // classified as SAME_PAGE) was leaving the FrameNavigationEntry with the
+  // classified as SAME_ENTRY) was leaving the FrameNavigationEntry with the
   // same document sequence number as the previous entry but updates the URL.
   // Doing a back session history navigation now will cause the browser to
   // consider it as same document because of this matching document sequence
@@ -8787,7 +8787,7 @@
         "/navigation_controller/simple_page_2.html"));
     NavigateFrameToURL(root, main_url_2);
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
     EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
         capturer.transition(), ui::PAGE_TRANSITION_LINK));
   }
@@ -9160,7 +9160,7 @@
     EXPECT_FALSE(observer.last_navigation_succeeded());
     EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE,
               observer.last_net_error_code());
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, observer.last_navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, observer.last_navigation_type());
     EXPECT_EQ(PAGE_TYPE_ERROR,
               controller.GetLastCommittedEntry()->GetPageType());
 
@@ -9177,7 +9177,7 @@
     EXPECT_FALSE(reload_observer.last_navigation_succeeded());
     EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE,
               reload_observer.last_net_error_code());
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE,
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY,
               reload_observer.last_navigation_type());
     EXPECT_EQ(PAGE_TYPE_ERROR,
               controller.GetLastCommittedEntry()->GetPageType());
@@ -9192,7 +9192,7 @@
     EXPECT_FALSE(same_url_observer.last_navigation_succeeded());
     EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE,
               same_url_observer.last_net_error_code());
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE,
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY,
               same_url_observer.last_navigation_type());
     EXPECT_EQ(PAGE_TYPE_ERROR,
               controller.GetLastCommittedEntry()->GetPageType());
@@ -9823,11 +9823,11 @@
     EXPECT_EQ(SiteInstance::GetSiteForURL(
                   shell()->web_contents()->GetBrowserContext(), url3),
               root->current_frame_host()->GetSiteInstance()->GetSiteURL());
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, capturer.navigation_type());
   } else {
     EXPECT_EQ(initial_site_instance,
               root->current_frame_host()->GetSiteInstance());
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, capturer.navigation_type());
   }
 }
 
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index a48249d..860eb90 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -1672,7 +1672,7 @@
 }
 
 // Two consecutive navigations for the same URL entered in should be considered
-// as SAME_PAGE navigation even when we are redirected to some other page.
+// as SAME_ENTRY navigation even when we are redirected to some other page.
 TEST_F(NavigationControllerTest, Redirect) {
   NavigationControllerImpl& controller = controller_impl();
 
@@ -1711,7 +1711,7 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
-  EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, observer.navigation_type());
+  EXPECT_EQ(NAVIGATION_TYPE_SAME_ENTRY, observer.navigation_type());
   EXPECT_EQ(controller.GetEntryCount(), 1);
   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   EXPECT_TRUE(controller.GetLastCommittedEntry());
@@ -1766,7 +1766,7 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
-  EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, observer.navigation_type());
+  EXPECT_EQ(NAVIGATION_TYPE_SAME_ENTRY, observer.navigation_type());
   EXPECT_EQ(controller.GetEntryCount(), 1);
   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   EXPECT_TRUE(controller.GetLastCommittedEntry());
@@ -1779,7 +1779,7 @@
   EXPECT_FALSE(controller.CanGoForward());
 }
 
-// A redirect right off the bat should be a NEW_PAGE.
+// A redirect right off the bat should be a NEW_ENTRY.
 TEST_F(NavigationControllerTest, ImmediateRedirect) {
   NavigationControllerImpl& controller = controller_impl();
 
@@ -1803,7 +1803,7 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
-  EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, observer.navigation_type());
+  EXPECT_EQ(NAVIGATION_TYPE_NEW_ENTRY, observer.navigation_type());
   EXPECT_EQ(controller.GetEntryCount(), 1);
   EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
   EXPECT_TRUE(controller.GetLastCommittedEntry());
@@ -1825,12 +1825,12 @@
 // This test is about what happens in such a race when that pending entry
 // replacement happens. If it happens, and the first load had the same URL as
 // the page before it, we must make sure that the replacement of the pending
-// entry correctly turns a SAME_PAGE classification into an EXISTING_PAGE one.
+// entry correctly turns a SAME_ENTRY classification into an EXISTING_ENTRY one.
 //
 // (This is a unit test rather than a browser test because it's not currently
 // possible to force this sequence of events with a browser test.)
 TEST_F(NavigationControllerTest,
-       NavigationTypeClassification_ExistingPageRace) {
+       NavigationTypeClassification_ExistingEntryRace) {
   NavigationControllerImpl& controller = controller_impl();
   const GURL url1("http://foo1");
   const GURL url2("http://foo2");
@@ -1855,7 +1855,7 @@
   // ... and now the renderer sends a commit for the first navigation.
   LoadCommittedDetailsObserver observer(contents());
   navigation1->Commit();
-  EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, observer.navigation_type());
+  EXPECT_EQ(NAVIGATION_TYPE_EXISTING_ENTRY, observer.navigation_type());
 }
 
 // Tests navigation via link click within a subframe. A new navigation entry
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 30cd8e5..c47bf328 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -664,7 +664,8 @@
   DCHECK(navigation_request);
 
   // Check if this is loadDataWithBaseUrl (which needs special treatment).
-  auto& common_params = navigation_request->common_params();
+  const mojom::CommonNavigationParams& common_params =
+      navigation_request->common_params();
   if (NavigationRequest::IsLoadDataWithBaseURL(common_params)) {
     // A (potentially attacker-controlled) renderer process should not be able
     // to use loadDataWithBaseUrl code path to initiate fetches on behalf of a
@@ -4373,7 +4374,7 @@
          !is_mhtml_subframe_loaded_from_achive;
 }
 
-bool NavigationRequest::IsWebSecureContext() const {
+bool NavigationRequest::IsWebSecureContext() {
   // Parent document, if it exists, must also be a secure context.
   RenderFrameHostImpl* parent = frame_tree_node_->parent();
   if (parent && !parent->is_web_secure_context()) {
@@ -4383,8 +4384,8 @@
   // For both regular and origin-sandboxed documents, the origin to use is the
   // origin of the URL to-be-committed. The spec makes a distinction between the
   // two only because it works backwards from a committed document.
-  return network::IsOriginPotentiallyTrustworthy(
-      url::Origin::Create(common_params_->url));
+  url::Origin origin = GetOriginForURLLoaderFactoryUnchecked(this);
+  return network::IsOriginPotentiallyTrustworthy(origin);
 }
 
 void NavigationRequest::UpdateClientSecurityStateInternals() {
@@ -4401,8 +4402,6 @@
   if (computed_ip_address_space != network::mojom::IPAddressSpace::kUnknown)
     policy_container_host_->SetIPAddressSpace(computed_ip_address_space);
 
-  is_web_secure_context_ = IsWebSecureContext();
-
   if (!base::FeatureList::IsEnabled(
           features::kBlockInsecurePrivateNetworkRequests)) {
     // No need to ask the content browser client, the feature is entirely off.
@@ -5214,9 +5213,9 @@
 }
 
 network::mojom::ClientSecurityStatePtr
-NavigationRequest::BuildClientSecurityState() const {
+NavigationRequest::BuildClientSecurityState() {
   auto client_security_state = network::mojom::ClientSecurityState::New();
-  client_security_state->is_web_secure_context = is_web_secure_context_;
+  client_security_state->is_web_secure_context = IsWebSecureContext();
   client_security_state->cross_origin_embedder_policy =
       cross_origin_embedder_policy_;
   client_security_state->ip_address_space =
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index c22481c..aba5509 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -657,7 +657,7 @@
     return response_should_be_rendered_;
   }
 
-  network::mojom::ClientSecurityStatePtr BuildClientSecurityState() const;
+  network::mojom::ClientSecurityStatePtr BuildClientSecurityState();
 
   bool ua_change_requires_reload() const { return ua_change_requires_reload_; }
 
@@ -780,7 +780,14 @@
   //          NavigationThrottle.
   bool NeedsUrlLoader();
 
-  bool is_web_secure_context() const { return is_web_secure_context_; }
+  // Returns whether the navigation will yield a secure context.
+  //
+  // This navigation's state should be at least |READY_TO_COMMIT|.
+  //
+  // See also |RenderFrameHostImpl::is_web_secure_context()|, which this value
+  // feeds into upon this navigation committing.
+  bool IsWebSecureContext();
+
   network::CrossOriginEmbedderPolicy cross_origin_embedder_policy() const {
     return cross_origin_embedder_policy_;
   }
@@ -1057,14 +1064,6 @@
   // redirect.
   void UpdateStateFollowingRedirect(const GURL& new_referrer_url);
 
-  // Returns whether the ready-to-commit navigation will yield a secure context.
-  //
-  // Helper for UpdateClientSecurityStateInternals().
-  //
-  // Implements the following algorithm:
-  // https://w3c.github.io/webappsec-secure-contexts/#is-settings-object-contextually-secure
-  bool IsWebSecureContext() const;
-
   // Updates the internals used to construct a ClientSecurityState during
   // ReadyToCommitNavigation().
   //
@@ -1566,7 +1565,6 @@
   // TODO(ahemery, titouan): Move some elements to the policy container or
   // rework inheritance.
   // https://crbug.com/1154729
-  bool is_web_secure_context_ = false;
   network::CrossOriginEmbedderPolicy cross_origin_embedder_policy_;
   network::mojom::PrivateNetworkRequestPolicy private_network_request_policy_ =
       network::mojom::PrivateNetworkRequestPolicy::kAllow;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 3d3a24b..8227ea98 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -2919,6 +2919,15 @@
   DCHECK(GetLastCommittedOrigin().opaque());
   DCHECK(isolation_info_.IsEmpty());
 
+  // If the document has a non-secure parent, then it is non-secure. Otherwise
+  // it depends if the creator has a potentially-trustworthy origin.
+  if (parent_ && !parent_->is_web_secure_context()) {
+    is_web_secure_context_ = false;
+  } else {
+    is_web_secure_context_ =
+        network::IsOriginPotentiallyTrustworthy(new_frame_creator);
+  }
+
   // Calculate and set |new_frame_origin|.
   bool new_frame_should_be_sandboxed =
       network::mojom::WebSandboxFlags::kOrigin ==
@@ -3865,10 +3874,10 @@
       new download::DownloadUrlParameters(blink_parameters->url,
                                           GetProcess()->GetID(),
                                           GetRoutingID(), traffic_annotation));
-  parameters->set_content_initiated(true);
+  parameters->set_content_initiated(!blink_parameters->is_context_menu_save);
   parameters->set_suggested_name(
       blink_parameters->suggested_name.value_or(base::string16()));
-  parameters->set_prompt(false);
+  parameters->set_prompt(blink_parameters->is_context_menu_save);
   parameters->set_cross_origin_redirects(
       blink_parameters->cross_origin_redirects);
   parameters->set_referrer(
@@ -8493,7 +8502,7 @@
 network::mojom::ClientSecurityStatePtr
 RenderFrameHostImpl::BuildClientSecurityState() const {
   auto client_security_state = network::mojom::ClientSecurityState::New();
-  client_security_state->is_web_secure_context = is_web_secure_context_;
+  client_security_state->is_web_secure_context = is_web_secure_context();
   client_security_state->cross_origin_embedder_policy =
       cross_origin_embedder_policy_;
   client_security_state->ip_address_space =
@@ -8933,8 +8942,13 @@
 
   cross_origin_opener_policy_ =
       navigation_request->coop_status().current_coop();
+
+  // Only apply some parameters if this is not the fake initial navigation,
+  // because the values set at construction time should remain unmodified.
   if (navigation_request->IsWaitingToCommit()) {
-    is_web_secure_context_ = navigation_request->is_web_secure_context();
+    // IsWebSecureContext() must only be called on ready-to-commit navigations.
+    is_web_secure_context_ = navigation_request->IsWebSecureContext();
+
     private_network_request_policy_ =
         navigation_request->private_network_request_policy();
     cross_origin_embedder_policy_ =
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index afb445f..3640a44 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -1888,13 +1888,15 @@
     return accessibility_fatal_error_count_;
   }
 
+  // Returns true if the current document is considered to be a secure context.
+  //
+  // See the field documentation for more details.
+  bool is_web_secure_context() const { return is_web_secure_context_; }
+
   // Builds and return a ClientSecurityState based on the internal
   // RenderFrameHostImpl state. This is never null.
   network::mojom::ClientSecurityStatePtr BuildClientSecurityState() const;
 
-  // Returns true if the current document is considered to be a secure context.
-  bool is_web_secure_context() const { return is_web_secure_context_; }
-
 #if BUILDFLAG(ENABLE_PLUGINS)
   void PepperInstanceClosed(int32_t instance_id);
   void PepperSetVolume(int32_t instance_id, double volume);
@@ -2700,6 +2702,19 @@
   // Track this frame's last committed origin.
   url::Origin last_committed_origin_;
 
+  // Whether the last committed document is a secure context.
+  //
+  // See: https://html.spec.whatwg.org/#secure-contexts.
+  //
+  // See also:
+  //  - |network::IsUrlPotentiallyTrustworthy()|
+  //  - |network::IsOriginPotentiallyTrustworthy()|
+  //
+  // WARNING: This does not behave exactly as specified in HTML. Instead it more
+  // closely follows the Blink implementation, which predates it, for
+  // consistency.
+  bool is_web_secure_context_ = false;
+
   network::CrossOriginEmbedderPolicy cross_origin_embedder_policy_;
 
   network::CrossOriginOpenerPolicy cross_origin_opener_policy_;
@@ -3233,16 +3248,8 @@
   // Salt for generating frame-specific media device IDs.
   std::string media_device_id_salt_base_;
 
-  // Below are security properties of the last committed document that are
-  // needed by the network service. Until then they have default or inherited
-  // values.
-
-  // The frame might not have committed a navigation yet. In this case, we need
-  // to make sure that the is_web_secure_context bit is correctly inherited at
-  // construction time in the RenderFrameHostImpl.
-  //
-  // TODO(crbug.com/1124346): Determine if this is correct, fix it if not.
-  bool is_web_secure_context_ = false;
+  // This is a security property of the last committed document that are
+  // needed by the network service. Until then it has a default value.
   network::mojom::PrivateNetworkRequestPolicy private_network_request_policy_ =
       network::mojom::PrivateNetworkRequestPolicy::kAllow;
 
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 8215e98..ec28b95 100644
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -4589,7 +4589,7 @@
 
 // Wraps the URLLoaderInterceptor method of the same name, asserts success.
 //
-// NOTE: ASSERT_* macros can only be used in functions returning void.
+// Note: ASSERT_* macros can only be used in functions returning void.
 void WriteResponseBody(base::StringPiece body,
                        network::mojom::URLLoaderClient* client) {
   ASSERT_EQ(content::URLLoaderInterceptor::WriteResponseBody(body, client),
@@ -4973,6 +4973,57 @@
 
 namespace {
 
+// Helper for CreateBlobURL() and CreateFilesystemURL().
+// ASSERT_* macros can only be used in functions returning void.
+void AssertResultIsString(const EvalJsResult& result) {
+  // We could skip this assert, but it helps in case of error.
+  ASSERT_EQ("", result.error);
+  // We could use result.value.is_string(), but this logs the actual type in
+  // case of mismatch.
+  ASSERT_EQ(base::Value::Type::STRING, result.value.type()) << result.value;
+}
+
+// Creates a blob containing dummy HTML, then returns its URL.
+// Executes javascript to do so in |frame_host|, which must not be nullptr.
+GURL CreateBlobURL(RenderFrameHostImpl* frame_host) {
+  EvalJsResult result = EvalJs(frame_host, R"(
+    const blob = new Blob(["foo"], {type: "text/html"});
+    URL.createObjectURL(blob)
+  )");
+
+  AssertResultIsString(result);
+  return GURL(result.ExtractString());
+}
+
+// Writes some dummy HTML to a file, then returns its `filesystem:` URL.
+// Executes javascript to do so in |frame_host|, which must not be nullptr.
+GURL CreateFilesystemURL(RenderFrameHostImpl* frame_host) {
+  EvalJsResult result = EvalJs(frame_host, R"(
+    // It seems anonymous async functions are not available yet, so we cannot
+    // use an immediately-invoked function expression.
+    async function run() {
+      const fs = await new Promise((resolve, reject) => {
+        window.webkitRequestFileSystem(window.TEMPORARY, 1024, resolve, reject);
+      });
+      const file = await new Promise((resolve, reject) => {
+        fs.root.getFile('hello.html', {create: true}, resolve, reject);
+      });
+      const writer = await new Promise((resolve, reject) => {
+        file.createWriter(resolve, reject);
+      });
+      await new Promise((resolve) => {
+        writer.onwriteend = resolve;
+        writer.write(new Blob(["foo"], {type: "text/html"}));
+      });
+      return file.toURL();
+    }
+    run()
+  )");
+
+  AssertResultIsString(result);
+  return GURL(result.ExtractString());
+}
+
 // Executes |script| to add a new child iframe to the given |parent| document.
 //
 // |parent| must not be nullptr.
@@ -4994,6 +5045,26 @@
   return parent->child_at(initial_child_count)->current_frame_host();
 }
 
+// Adds a child iframe sourced from |url| to the given |parent| document.
+//
+// |parent| must not be nullptr.
+RenderFrameHostImpl* AddChildFromURL(RenderFrameHostImpl* parent,
+                                     const GURL& url) {
+  std::string script_template = R"(
+    new Promise((resolve) => {
+      const iframe = document.createElement("iframe");
+      iframe.src = $1;
+      iframe.onload = _ => { resolve(true); };
+      document.body.appendChild(iframe);
+    })
+  )";
+  return AddChildWithScript(parent, JsReplace(script_template, url));
+}
+
+RenderFrameHostImpl* AddChildFromAboutBlank(RenderFrameHostImpl* parent) {
+  return AddChildFromURL(parent, GURL("about:blank"));
+}
+
 RenderFrameHostImpl* AddChildInitialEmptyDoc(RenderFrameHostImpl* parent) {
   return AddChildWithScript(parent, R"(
     const iframe = document.createElement("iframe");
@@ -5003,17 +5074,6 @@
   )");
 }
 
-RenderFrameHostImpl* AddChildFromAboutBlank(RenderFrameHostImpl* parent) {
-  return AddChildWithScript(parent, R"(
-    new Promise((resolve) => {
-      const iframe = document.createElement("iframe");
-      iframe.src = "about:blank";  // Superfluous, but being explicit is nice.
-      iframe.onload = _ => { resolve(true); };
-      document.body.appendChild(iframe);
-    })
-  )");
-}
-
 RenderFrameHostImpl* AddChildFromSrcdoc(RenderFrameHostImpl* parent) {
   return AddChildWithScript(parent, R"(
     new Promise((resolve) => {
@@ -5026,67 +5086,77 @@
 }
 
 RenderFrameHostImpl* AddChildFromDataURL(RenderFrameHostImpl* parent) {
-  return AddChildWithScript(parent, R"(
-    new Promise((resolve) => {
-      const iframe = document.createElement("iframe");
-      iframe.src = "data:text/html,foo";
-      iframe.onload = _ => { resolve(true); };
-      document.body.appendChild(iframe);
-    })
-  )");
+  return AddChildFromURL(parent, GURL("data:text/html,foo"));
 }
 
 RenderFrameHostImpl* AddChildFromJavascriptURL(RenderFrameHostImpl* parent) {
-  return AddChildWithScript(parent, R"(
-    new Promise((resolve) => {
-      const iframe = document.createElement("iframe");
-      iframe.src = "javascript:'foo'";
-      iframe.onload = _ => { resolve(true); };
-      document.body.appendChild(iframe);
-    })
-  )");
+  return AddChildFromURL(parent, GURL("javascript:'foo'"));
 }
 
 RenderFrameHostImpl* AddChildFromBlob(RenderFrameHostImpl* parent) {
-  return AddChildWithScript(parent, R"(
-    new Promise((resolve) => {
-      const blob = new Blob(["foo"], {type: "text/html"});
-      const iframe = document.createElement("iframe");
-      iframe.src = URL.createObjectURL(blob);
-      iframe.onload = _ => { resolve(true); };
-      document.body.appendChild(iframe);
-    })
-  )");
+  GURL blob_url = CreateBlobURL(parent);
+  return AddChildFromURL(parent, blob_url);
 }
 
 RenderFrameHostImpl* AddChildFromFilesystem(RenderFrameHostImpl* parent) {
-  return AddChildWithScript(parent, R"(
-    // It seems anonymous async functions are not available yet, so we cannot
-    // use an immediately-invoked function expression.
-    async function run() {
-      const fs = await new Promise((resolve, reject) => {
-        window.webkitRequestFileSystem(window.TEMPORARY, 1024, resolve, reject);
-      });
-      const file = await new Promise((resolve, reject) => {
-        fs.root.getFile('hello.html', {create: true}, resolve, reject);
-      });
-      const writer = await new Promise((resolve, reject) => {
-        file.createWriter(resolve, reject);
-      });
-      await new Promise((resolve) => {
-        writer.onwriteend = resolve;
-        writer.write(new Blob(["foo"], {type: "text/html"}));
-      });
-      await new Promise((resolve) => {
-        const iframe = document.createElement("iframe");
-        iframe.src = file.toURL();
-        iframe.onload = resolve;
-        document.body.appendChild(iframe);
-      });
-      return true;
-    }
-    run()
-  )");
+  GURL fs_url = CreateFilesystemURL(parent);
+  return AddChildFromURL(parent, fs_url);
+}
+
+// Returns the main frame RenderFrameHostImpl in the given |shell|.
+//
+// |shell| must not be nullptr.
+//
+// Helper for OpenWindow*().
+RenderFrameHostImpl* GetMainFrameHostImpl(Shell* shell) {
+  return static_cast<RenderFrameHostImpl*>(
+      shell->web_contents()->GetMainFrame());
+}
+
+// Opens a new window from within |parent|, pointed at the given |url|.
+// Waits until the openee window has navigated to |url|, then returns a pointer
+// to its main frame RenderFrameHostImpl.
+//
+// |parent| must not be nullptr.
+RenderFrameHostImpl* OpenWindowFromURL(RenderFrameHostImpl* parent,
+                                       const GURL& url) {
+  return GetMainFrameHostImpl(OpenPopup(parent, url, "child"));
+}
+
+RenderFrameHostImpl* OpenWindowFromAboutBlank(RenderFrameHostImpl* parent) {
+  return OpenWindowFromURL(parent, GURL("about:blank"));
+}
+
+RenderFrameHostImpl* OpenWindowInitialEmptyDoc(RenderFrameHostImpl* parent) {
+  // Note: We do not use OpenWindowFromURL() because we do not want to wait for
+  // a navigation - none will commit.
+
+  ShellAddedObserver observer;
+
+  EXPECT_TRUE(ExecJs(parent, R"(
+    window.open("/nocontent");
+  )"));
+
+  return GetMainFrameHostImpl(observer.GetShell());
+}
+
+RenderFrameHostImpl* OpenWindowFromJavascriptURL(RenderFrameHostImpl* parent) {
+  // Note: We do not use OpenWindowFromURL() because we do not want to wait for
+  // a navigation, since the `javascript:` URL will not commit (`about:blank`
+  // will).
+
+  ShellAddedObserver observer;
+
+  EXPECT_TRUE(ExecJs(parent, R"(
+    window.open("javascript:'foo'");
+  )"));
+
+  return GetMainFrameHostImpl(observer.GetShell());
+}
+
+RenderFrameHostImpl* OpenWindowFromBlob(RenderFrameHostImpl* parent) {
+  GURL blob_url = CreateBlobURL(parent);
+  return OpenWindowFromURL(parent, blob_url);
 }
 
 }  // namespace
@@ -5127,6 +5197,40 @@
 
 IN_PROC_BROWSER_TEST_F(
     RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsAddressSpaceForAboutBlankFromPublic) {
+  EXPECT_TRUE(NavigateToURL(
+      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromAboutBlank(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsAddressSpaceForAboutBlankFromLocal) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromAboutBlank(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_EQ(network::mojom::IPAddressSpace::kLocal,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
     IframeInheritsAddressSpaceForInitialEmptyDocFromPublic) {
   EXPECT_TRUE(NavigateToURL(
       shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
@@ -5161,6 +5265,40 @@
 
 IN_PROC_BROWSER_TEST_F(
     RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsAddressSpaceForInitialEmptyDocFromPublic) {
+  EXPECT_TRUE(NavigateToURL(
+      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowInitialEmptyDoc(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsAddressSpaceForInitialEmptyDocFromLocal) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowInitialEmptyDoc(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_EQ(network::mojom::IPAddressSpace::kLocal,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
     IframeInheritsAddressSpaceForAboutSrcdocFromPublic) {
   EXPECT_TRUE(NavigateToURL(
       shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
@@ -5265,6 +5403,40 @@
 
 IN_PROC_BROWSER_TEST_F(
     RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsAddressSpaceForJavascriptURLFromPublic) {
+  EXPECT_TRUE(NavigateToURL(
+      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromJavascriptURL(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsAddressSpaceForJavascriptURLFromLocal) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromJavascriptURL(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_EQ(network::mojom::IPAddressSpace::kLocal,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
     IframeInheritsAddressSpaceForBlobURLFromPublic) {
   EXPECT_TRUE(NavigateToURL(
       shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
@@ -5299,6 +5471,40 @@
 
 IN_PROC_BROWSER_TEST_F(
     RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsAddressSpaceForBlobURLFromPublic) {
+  EXPECT_TRUE(NavigateToURL(
+      shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromBlob(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsAddressSpaceForBlobURLFromLocal) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromBlob(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_EQ(network::mojom::IPAddressSpace::kLocal,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
     IframeInheritsAddressSpaceForFilesystemURLFromPublic) {
   EXPECT_TRUE(NavigateToURL(
       shell(), SecureTreatAsPublicAddressURL(*embedded_test_server())));
@@ -5340,12 +5546,13 @@
   RenderFrameHostImpl* child_frame = AddChildFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_TRUE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
 
-  // TODO(https://crbug.com/1126856): Expect true once inheritance is fixed.
-  EXPECT_FALSE(security_state->is_web_secure_context);
+  EXPECT_TRUE(security_state->is_web_secure_context);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -5357,6 +5564,8 @@
   RenderFrameHostImpl* child_frame = AddChildFromAboutBlank(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_FALSE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
@@ -5366,6 +5575,42 @@
 
 IN_PROC_BROWSER_TEST_F(
     RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsSecureContextForAboutBlankFromSecure) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromAboutBlank(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  EXPECT_TRUE(window->is_web_secure_context());
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_TRUE(security_state->is_web_secure_context);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsSecureContextForAboutBlankFromInsecure) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromAboutBlank(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  EXPECT_FALSE(window->is_web_secure_context());
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_FALSE(security_state->is_web_secure_context);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
     IframeInheritsSecureContextForInitialEmptyDocFromSecure) {
   EXPECT_TRUE(
       NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
@@ -5373,12 +5618,13 @@
   RenderFrameHostImpl* child_frame = AddChildInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_TRUE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
 
-  // TODO(https://crbug.com/1126856): Expect true once inheritance is fixed.
-  EXPECT_FALSE(security_state->is_web_secure_context);
+  EXPECT_TRUE(security_state->is_web_secure_context);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -5390,6 +5636,8 @@
   RenderFrameHostImpl* child_frame = AddChildInitialEmptyDoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_FALSE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
@@ -5399,6 +5647,42 @@
 
 IN_PROC_BROWSER_TEST_F(
     RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsSecureContextForInitialEmptyDocFromSecure) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowInitialEmptyDoc(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  EXPECT_TRUE(window->is_web_secure_context());
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_TRUE(security_state->is_web_secure_context);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsSecureContextForInitialEmptyDocFromInsecure) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowInitialEmptyDoc(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  EXPECT_FALSE(window->is_web_secure_context());
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_FALSE(security_state->is_web_secure_context);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
     IframeInheritsSecureContextForAboutSrcdocFromSecure) {
   EXPECT_TRUE(
       NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
@@ -5406,12 +5690,13 @@
   RenderFrameHostImpl* child_frame = AddChildFromSrcdoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_TRUE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
 
-  // TODO(https://crbug.com/1126856): Expect true once inheritance is fixed.
-  EXPECT_FALSE(security_state->is_web_secure_context);
+  EXPECT_TRUE(security_state->is_web_secure_context);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -5423,6 +5708,8 @@
   RenderFrameHostImpl* child_frame = AddChildFromSrcdoc(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_FALSE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
@@ -5439,11 +5726,23 @@
   RenderFrameHostImpl* child_frame = AddChildFromDataURL(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  // A document loaded from a `data:` URL is never a secure context according to
+  // the spec [1] unless it is origin-sandboxed and its parent is a secure
+  // context itself.
+  // That being said, there exists a web platform test [2] that asserts the
+  // contrary. Then again, it is failing on all major browsers as of
+  // 2021-01-08...
+  //
+  // [1]
+  // https://w3c.github.io/webappsec-secure-contexts/#is-settings-object-contextually-secure
+  // [2]
+  // https://wpt.fyi/results/secure-contexts/basic-popup-and-iframe-tests.https.html
+  EXPECT_FALSE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
 
-  // TODO(https://crbug.com/1126856): Expect true once inheritance is fixed.
   EXPECT_FALSE(security_state->is_web_secure_context);
 }
 
@@ -5456,6 +5755,8 @@
   RenderFrameHostImpl* child_frame = AddChildFromDataURL(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_FALSE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
@@ -5473,16 +5774,53 @@
       AddChildFromJavascriptURL(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_TRUE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
 
-  // TODO(https://crbug.com/1126856): Expect true once inheritance is fixed.
+  EXPECT_TRUE(security_state->is_web_secure_context);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsSecureContextForJavascriptURLFromInsecure) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromJavascriptURL(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  EXPECT_FALSE(window->is_web_secure_context());
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
   EXPECT_FALSE(security_state->is_web_secure_context);
 }
 
 IN_PROC_BROWSER_TEST_F(
     RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsSecureContextForJavascriptURLFromSecure) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromJavascriptURL(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  EXPECT_TRUE(window->is_web_secure_context());
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_TRUE(security_state->is_web_secure_context);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
     IframeInheritsSecureContextForJavascriptURLFromInsecure) {
   EXPECT_TRUE(
       NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
@@ -5491,6 +5829,8 @@
       AddChildFromJavascriptURL(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_FALSE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
@@ -5507,6 +5847,8 @@
   RenderFrameHostImpl* child_frame = AddChildFromBlob(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_TRUE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
@@ -5523,6 +5865,8 @@
   RenderFrameHostImpl* child_frame = AddChildFromBlob(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_FALSE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
@@ -5532,6 +5876,42 @@
 
 IN_PROC_BROWSER_TEST_F(
     RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsSecureContextForBlobURLFromSecure) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromBlob(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  EXPECT_TRUE(window->is_web_secure_context());
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_TRUE(security_state->is_web_secure_context);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
+    OpeneeInheritsSecureContextForBlobURLFromInsecure) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), InsecureDefaultURL(*embedded_test_server())));
+
+  RenderFrameHostImpl* window = OpenWindowFromBlob(root_frame_host());
+  ASSERT_NE(nullptr, window);
+
+  EXPECT_FALSE(window->is_web_secure_context());
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      window->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_FALSE(security_state->is_web_secure_context);
+}
+
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTestWithInsecurePrivateNetworkRequestsBlocked,
     IframeInheritsSecureContextForFilesystemURLFromSecure) {
   EXPECT_TRUE(
       NavigateToURL(shell(), SecureDefaultURL(*embedded_test_server())));
@@ -5539,6 +5919,8 @@
   RenderFrameHostImpl* child_frame = AddChildFromFilesystem(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_TRUE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
@@ -5555,6 +5937,8 @@
   RenderFrameHostImpl* child_frame = AddChildFromFilesystem(root_frame_host());
   ASSERT_NE(nullptr, child_frame);
 
+  EXPECT_FALSE(child_frame->is_web_secure_context());
+
   const network::mojom::ClientSecurityStatePtr security_state =
       child_frame->BuildClientSecurityState();
   ASSERT_FALSE(security_state.is_null());
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index 910338af..1e74340 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -2796,41 +2796,6 @@
   int previous_routing_id =
       GetReplacementRoutingId(existing_proxy, render_frame_host);
 
-  // TOOD(https://crbug.com/1163509): Delete this.
-  if (previous_routing_id == MSG_ROUTING_NONE &&
-      parent_routing_id == MSG_ROUTING_NONE) {
-    // If this was true we would have CHECK-failed above.
-    SCOPED_CRASH_KEY_BOOL("bug-1163509", "has_parent",
-                          !!frame_tree_node_->parent());
-    // If this was true we would have CHECK-failed in GetReplacementRoutingId.
-    SCOPED_CRASH_KEY_BOOL("bug-1163509", "existing_proxy", !!existing_proxy);
-    // This must be true since existing_proxy is false and previous_routing_id
-    // is NONE.
-    SCOPED_CRASH_KEY_BOOL("bug-1163509", "SameSiteInstance",
-                          render_frame_host->GetSiteInstance() ==
-                              current_frame_host()->GetSiteInstance());
-    SCOPED_CRASH_KEY_STRING64("bug-1163509", "old->SiteInstance",
-                              current_frame_host()
-                                  ->GetSiteInstance()
-                                  ->GetSiteURL()
-                                  .possibly_invalid_spec());
-    SCOPED_CRASH_KEY_STRING64("bug-1163509", "new->SiteInstance",
-                              render_frame_host->GetSiteInstance()
-                                  ->GetSiteURL()
-                                  .possibly_invalid_spec());
-    SCOPED_CRASH_KEY_BOOL("bug-1163509", "IsRenderFrameLive",
-                          current_frame_host()->IsRenderFrameLive());
-    // If the frame is live then the previous_routing_id comes from the current
-    // RFH.
-    SCOPED_CRASH_KEY_NUMBER("bug-1163509", "old->GetRoutingID",
-                            current_frame_host()->GetRoutingID());
-    SCOPED_CRASH_KEY_NUMBER("bug-1163509", "new->GetRoutingID",
-                            render_frame_host->GetRoutingID());
-    SCOPED_CRASH_KEY_BOOL("bug-1163509", "must_be_replaced",
-                          current_frame_host()->must_be_replaced());
-    NOTREACHED();
-    base::debug::DumpWithoutCrashing();
-  }
   return render_frame_host->CreateRenderFrame(
       previous_routing_id, opener_frame_token, parent_routing_id,
       previous_sibling_routing_id);
diff --git a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
index a05fb318..23aa389 100644
--- a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
@@ -4676,9 +4676,9 @@
     reload_observer.Wait();
     EXPECT_FALSE(reload_observer.last_navigation_succeeded());
     // TODO(nasko): Investigate making a failing reload of a successful
-    // navigation be classified as NEW_PAGE instead, since with error page
+    // navigation be classified as NEW_ENTRY instead, since with error page
     // isolation it involves a SiteInstance swap.
-    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_PAGE,
+    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_ENTRY,
               reload_observer.last_navigation_type());
   }
   EXPECT_EQ(3, nav_controller.GetEntryCount());
@@ -4698,7 +4698,7 @@
     shell()->web_contents()->GetController().Reload(ReloadType::NORMAL, false);
     reload_observer.Wait();
     EXPECT_FALSE(reload_observer.last_navigation_succeeded());
-    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_PAGE,
+    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_ENTRY,
               reload_observer.last_navigation_type());
   }
   EXPECT_EQ(process_id,
@@ -4714,10 +4714,10 @@
     shell()->web_contents()->GetController().Reload(ReloadType::NORMAL, false);
     reload_observer.Wait();
     EXPECT_TRUE(reload_observer.last_navigation_succeeded());
-    // The successful reload should be classified as a NEW_PAGE navigation
+    // The successful reload should be classified as a NEW_ENTRY navigation
     // with replacement, since it needs to stay at the same entry in session
     // history, but needs a new entry because of the change in SiteInstance.
-    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_NEW_PAGE,
+    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_NEW_ENTRY,
               reload_observer.last_navigation_type());
   }
   EXPECT_EQ(3, nav_controller.GetEntryCount());
@@ -4741,9 +4741,9 @@
     reload_observer.Wait();
     EXPECT_FALSE(reload_observer.last_navigation_succeeded());
     // TODO(nasko): Investigate making a failing reload of a successful
-    // navigation be classified as NEW_PAGE instead, since with error page
+    // navigation be classified as NEW_ENTRY instead, since with error page
     // isolation it involves a SiteInstance swap.
-    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_PAGE,
+    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_ENTRY,
               reload_observer.last_navigation_type());
   }
   EXPECT_EQ(3, nav_controller.GetEntryCount());
@@ -4764,8 +4764,8 @@
     reload_observer.Wait();
     EXPECT_TRUE(reload_observer.last_navigation_succeeded());
     // TODO(nasko): Investigate making renderer initiated reloads that change
-    // SiteInstance be classified as NEW_PAGE as well.
-    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_PAGE,
+    // SiteInstance be classified as NEW_ENTRY as well.
+    EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_ENTRY,
               reload_observer.last_navigation_type());
   }
   EXPECT_EQ(3, nav_controller.GetEntryCount());
@@ -5064,14 +5064,14 @@
     EXPECT_EQ(redirect_url, nav_controller.GetLastCommittedEntry()->GetURL());
     EXPECT_EQ(second_url, nav_controller.GetEntryAtIndex(1)->GetURL());
     if (AreAllSitesIsolatedForTesting()) {
-      // The successful reload should be classified as a NEW_PAGE navigation
+      // The successful reload should be classified as a NEW_ENTRY navigation
       // with replacement, since it needs to stay at the same entry in session
       // history, but needs a new entry because of the change in SiteInstance.
       // (the same as expectations in the ErrorPageNavigationReload test above).
-      EXPECT_EQ(NavigationType::NAVIGATION_TYPE_NEW_PAGE,
+      EXPECT_EQ(NavigationType::NAVIGATION_TYPE_NEW_ENTRY,
                 reload_observer.last_navigation_type());
     } else {
-      EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_PAGE,
+      EXPECT_EQ(NavigationType::NAVIGATION_TYPE_EXISTING_ENTRY,
                 reload_observer.last_navigation_type());
     }
   }
@@ -6869,12 +6869,12 @@
             site_instance_2_history_nav->GetProcess());
 }
 
-// If the navigation is classified as NAVIGATION_TYPE_SAME_PAGE, or is a same
+// If the navigation is classified as NAVIGATION_TYPE_SAME_ENTRY, or is a same
 // document navigation, we should not do a proactive BrowsingInstance swap.
-// TODO(crbug.com/536102): NAVIGATION_TYPE_SAME_PAGE will be removed in the
+// TODO(crbug.com/536102): NAVIGATION_TYPE_SAME_ENTRY will be removed in the
 // future, so we should update this test.
 IN_PROC_BROWSER_TEST_P(ProactivelySwapBrowsingInstancesSameSiteTest,
-                       SamePageAndSameDocumentNavigationDoesNotSwap) {
+                       SameEntryAndSameDocumentNavigationDoesNotSwap) {
   ASSERT_TRUE(embedded_test_server()->Start());
   WebContentsImpl* web_contents =
       static_cast<WebContentsImpl*>(shell()->web_contents());
@@ -6887,7 +6887,7 @@
           web_contents->GetMainFrame()->GetSiteInstance());
 
   // 2) Navigate from title1.html#foo to title1.html.
-  // This is a different-document, same-page navigation.
+  // This is a different-document, same-entry navigation.
   EXPECT_TRUE(
       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
   scoped_refptr<SiteInstanceImpl> site_instance_2 =
@@ -6898,7 +6898,7 @@
   EXPECT_EQ(site_instance_1, site_instance_2);
 
   // 3) Navigate from title1.html to title1.html.
-  // This is a different-document, same-page navigation.
+  // This is a different-document, same-entry navigation.
   EXPECT_TRUE(
       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
   scoped_refptr<SiteInstanceImpl> site_instance_3 =
@@ -6942,7 +6942,7 @@
   EXPECT_EQ(site_instance_5, site_instance_6);
 
   // 7) Do a history navigation from title1.html#bar to title1.html#foo.
-  // This is a different-document, same-page history navigation.
+  // This is a different-document, same-entry history navigation.
   shell()->web_contents()->GetController().GoBack();
   EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
   scoped_refptr<SiteInstanceImpl> site_instance_7 =
diff --git a/content/browser/sms/webotp_service.cc b/content/browser/sms/webotp_service.cc
index 7fba17e..5f3ecab 100644
--- a/content/browser/sms/webotp_service.cc
+++ b/content/browser/sms/webotp_service.cc
@@ -246,14 +246,14 @@
 void WebOTPService::NavigationEntryCommitted(
     const content::LoadCommittedDetails& load_details) {
   switch (load_details.type) {
-    case NavigationType::NAVIGATION_TYPE_NEW_PAGE:
+    case NavigationType::NAVIGATION_TYPE_NEW_ENTRY:
       RecordDestroyedReason(WebOTPServiceDestroyedReason::kNavigateNewPage);
       break;
-    case NavigationType::NAVIGATION_TYPE_EXISTING_PAGE:
+    case NavigationType::NAVIGATION_TYPE_EXISTING_ENTRY:
       RecordDestroyedReason(
           WebOTPServiceDestroyedReason::kNavigateExistingPage);
       break;
-    case NavigationType::NAVIGATION_TYPE_SAME_PAGE:
+    case NavigationType::NAVIGATION_TYPE_SAME_ENTRY:
       RecordDestroyedReason(WebOTPServiceDestroyedReason::kNavigateSamePage);
       break;
     default:
diff --git a/content/browser/web_package/web_bundle_browsertest.cc b/content/browser/web_package/web_bundle_browsertest.cc
index b9282e96..3f8bb99d9 100644
--- a/content/browser/web_package/web_bundle_browsertest.cc
+++ b/content/browser/web_package/web_bundle_browsertest.cc
@@ -847,14 +847,14 @@
       get_url_for_bundle.Run(url_origin.Resolve("/top-page/")), "Ready");
   RunScriptAndObserveNavigation(
       "Navigate to /1-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/1-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/1-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
       "/1-page/ from wbn, /1-page/script from wbn");
   RunScriptAndObserveNavigation(
       "Navigate to /2-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/2-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/2-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -862,7 +862,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /1-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
@@ -870,7 +870,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /top-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/top-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/top-page/") /* expected_last_inner_url */,
@@ -878,14 +878,14 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /1-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
       "/1-page/ from wbn, /1-page/script from wbn");
   RunScriptAndObserveNavigation(
       "Reload /1-page/", web_contents, web_contents /* execution_target */,
-      "location.reload();", {NAVIGATION_TYPE_EXISTING_PAGE},
+      "location.reload();", {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
@@ -893,7 +893,7 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /2-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -921,14 +921,14 @@
       get_url_for_bundle.Run(url_origin.Resolve("/top-page/")), "Ready");
   RunScriptAndObserveNavigation(
       "Navigate to /1-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/1-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/1-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
       "/1-page/ from wbn, /1-page/script from wbn");
   RunScriptAndObserveNavigation(
       "Navigate to /2-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/2-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/2-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -947,21 +947,21 @@
   // even if the page is in the web bundle.
   RunScriptAndObserveNavigation(
       "Navigate to /4-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/4-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/4-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       url_origin.Resolve("/4-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/4-page/") /* expected_last_inner_url */,
       "/4-page/ from server, /4-page/script from server");
   RunScriptAndObserveNavigation(
       "Back navigate to /3-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       url_origin.Resolve("/3-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/3-page/") /* expected_last_inner_url */,
       "/3-page/ from server, /3-page/script from server");
   RunScriptAndObserveNavigation(
       "Back navigate to /2-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -969,7 +969,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /1-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
@@ -977,7 +977,7 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /2-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -985,14 +985,14 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /3-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       url_origin.Resolve("/3-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/3-page/") /* expected_last_inner_url */,
       "/3-page/ from server, /3-page/script from server");
   RunScriptAndObserveNavigation(
       "Forward navigate to /4-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       url_origin.Resolve("/4-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/4-page/") /* expected_last_inner_url */,
       "/4-page/ from server, /4-page/script from server");
@@ -1019,14 +1019,14 @@
       get_url_for_bundle.Run(url_origin.Resolve("/top-page/")), "Ready");
   RunScriptAndObserveNavigation(
       "Navigate to /1-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/1-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/1-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
       "/1-page/ from wbn, /1-page/script from wbn");
   RunScriptAndObserveNavigation(
       "Navigate to /2-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/2-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/2-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -1034,7 +1034,7 @@
   RunScriptAndObserveNavigation(
       "Navigate to /server-page/", web_contents,
       web_contents /* execution_target */, "location.href = '/server-page/';",
-      {NAVIGATION_TYPE_NEW_PAGE},
+      {NAVIGATION_TYPE_NEW_ENTRY},
       url_origin.Resolve("/server-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/server-page/") /* expected_last_inner_url */,
       "/server-page/ from server, /server-page/script from server");
@@ -1042,21 +1042,21 @@
   // even if the page is in the web bundle.
   RunScriptAndObserveNavigation(
       "Navigate to /3-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/3-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/3-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       url_origin.Resolve("/3-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/3-page/") /* expected_last_inner_url */,
       "/3-page/ from server, /3-page/script from server");
   RunScriptAndObserveNavigation(
       "Back navigate to /server-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       url_origin.Resolve("/server-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/server-page/") /* expected_last_inner_url */,
       "/server-page/ from server, /server-page/script from server");
   RunScriptAndObserveNavigation(
       "Back navigate to /2-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -1064,7 +1064,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /1-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
@@ -1072,7 +1072,7 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /2-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -1080,14 +1080,14 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /server-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       url_origin.Resolve("/server-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/server-page/") /* expected_last_inner_url */,
       "/server-page/ from server, /server-page/script from server");
   RunScriptAndObserveNavigation(
       "Forward navigate to /3-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       url_origin.Resolve("/3-page/") /* expected_last_comitted_url */,
       url_origin.Resolve("/3-page/") /* expected_last_inner_url */,
       "/3-page/ from server, /3-page/script from server");
@@ -1111,7 +1111,7 @@
       get_url_for_bundle.Run(url_origin.Resolve("/top-page/")), "Ready");
   RunScriptAndObserveNavigation(
       "Navigate to /1-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/1-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/1-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
@@ -1119,7 +1119,7 @@
   RunScriptAndObserveNavigation(
       "Navigate to /1-page/#hash1", web_contents,
       web_contents /* execution_target */, "location.href = '#hash1';",
-      {NAVIGATION_TYPE_NEW_PAGE},
+      {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/1-page/#hash1")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/#hash1") /* expected_last_inner_url */,
@@ -1127,14 +1127,14 @@
   RunScriptAndObserveNavigation(
       "Navigate to /1-page/#hash2", web_contents,
       web_contents /* execution_target */, "location.href = '#hash2';",
-      {NAVIGATION_TYPE_NEW_PAGE},
+      {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/1-page/#hash2")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/1-page/#hash2") /* expected_last_inner_url */,
       "/1-page/ from wbn, /1-page/script from wbn");
   RunScriptAndObserveNavigation(
       "Navigate to /2-page/", web_contents, web_contents /* execution_target */,
-      "location.href = '/2-page/';", {NAVIGATION_TYPE_NEW_PAGE},
+      "location.href = '/2-page/';", {NAVIGATION_TYPE_NEW_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url  */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -1142,7 +1142,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /1-page/#hash2", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/1-page/#hash2")) /* expected_last_comitted_url */,
       url_origin.Resolve("/1-page/#hash2") /* expected_last_inner_url */,
@@ -1150,7 +1150,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /1-page/#hash1", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/1-page/#hash1")) /* expected_last_comitted_url */,
       url_origin.Resolve("/1-page/#hash1") /* expected_last_inner_url */,
@@ -1158,7 +1158,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /1-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/1-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/1-page/") /* expected_last_inner_url */,
@@ -1166,7 +1166,7 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /1-page/#hash1", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/1-page/#hash1")) /* expected_last_comitted_url */,
       url_origin.Resolve("/1-page/#hash1") /* expected_last_inner_url */,
@@ -1174,7 +1174,7 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /1-page/#hash2", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/1-page/#hash2")) /* expected_last_comitted_url */,
       url_origin.Resolve("/1-page/#hash2") /* expected_last_inner_url */,
@@ -1182,7 +1182,7 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /2-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/2-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/2-page/") /* expected_last_inner_url */,
@@ -1220,7 +1220,7 @@
       "Navigate to /iframe-test-page/", web_contents,
       web_contents /* execution_target */,
       "location.href = '/iframe-test-page/';",
-      {NAVIGATION_TYPE_NEW_PAGE, NAVIGATION_TYPE_AUTO_SUBFRAME},
+      {NAVIGATION_TYPE_NEW_ENTRY, NAVIGATION_TYPE_AUTO_SUBFRAME},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/iframe-test-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/iframe-test-page/") /* expected_last_inner_url */,
@@ -1253,7 +1253,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /top-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/top-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/top-page/") /* expected_last_inner_url */,
@@ -1262,7 +1262,7 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /iframe-test-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE, NAVIGATION_TYPE_AUTO_SUBFRAME},
+      {NAVIGATION_TYPE_EXISTING_ENTRY, NAVIGATION_TYPE_AUTO_SUBFRAME},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/iframe-test-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/iframe-test-page/") /* expected_last_inner_url */,
@@ -1297,7 +1297,7 @@
       "Navigate to /iframe-test-page/", web_contents,
       web_contents /* execution_target */,
       "location.href = '/iframe-test-page/';",
-      {NAVIGATION_TYPE_NEW_PAGE, NAVIGATION_TYPE_AUTO_SUBFRAME},
+      {NAVIGATION_TYPE_NEW_ENTRY, NAVIGATION_TYPE_AUTO_SUBFRAME},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/iframe-test-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/iframe-test-page/") /* expected_last_inner_url */,
@@ -1347,7 +1347,7 @@
       "Navigate to /iframe-test-page/", web_contents,
       web_contents /* execution_target */,
       "location.href = '/iframe-test-page/';",
-      {NAVIGATION_TYPE_NEW_PAGE, NAVIGATION_TYPE_AUTO_SUBFRAME},
+      {NAVIGATION_TYPE_NEW_ENTRY, NAVIGATION_TYPE_AUTO_SUBFRAME},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/iframe-test-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/iframe-test-page/") /* expected_last_inner_url */,
@@ -1411,7 +1411,7 @@
       "Navigate to /iframe-test-page/", web_contents,
       web_contents /* execution_target */,
       "location.href = '/iframe-test-page/';",
-      {NAVIGATION_TYPE_NEW_PAGE, NAVIGATION_TYPE_AUTO_SUBFRAME},
+      {NAVIGATION_TYPE_NEW_ENTRY, NAVIGATION_TYPE_AUTO_SUBFRAME},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/iframe-test-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/iframe-test-page/") /* expected_last_inner_url */,
@@ -1500,7 +1500,7 @@
   RunScriptAndObserveNavigation(
       "Back navigate to /top-page/", web_contents,
       web_contents /* execution_target */, "history.back();",
-      {NAVIGATION_TYPE_EXISTING_PAGE},
+      {NAVIGATION_TYPE_EXISTING_ENTRY},
       get_url_for_bundle.Run(
           url_origin.Resolve("/top-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/top-page/") /* expected_last_inner_url */,
@@ -1509,7 +1509,7 @@
   RunScriptAndObserveNavigation(
       "Forward navigate to /iframe-test-page/", web_contents,
       web_contents /* execution_target */, "history.forward();",
-      {NAVIGATION_TYPE_EXISTING_PAGE, NAVIGATION_TYPE_AUTO_SUBFRAME},
+      {NAVIGATION_TYPE_EXISTING_ENTRY, NAVIGATION_TYPE_AUTO_SUBFRAME},
       get_url_for_bundle.Run(url_origin.Resolve(
           "/iframe-test-page/")) /* expected_last_comitted_url */,
       url_origin.Resolve("/iframe-test-page/") /* expected_last_inner_url */,
diff --git a/content/child/webthemeengine_impl_android.cc b/content/child/webthemeengine_impl_android.cc
index a6be4c16..8e6ddcc1 100644
--- a/content/child/webthemeengine_impl_android.cc
+++ b/content/child/webthemeengine_impl_android.cc
@@ -59,6 +59,8 @@
           extra_params->text_field.is_listbox;
       native_theme_extra_params->text_field.background_color =
           extra_params->text_field.background_color;
+      native_theme_extra_params->text_field.has_border =
+          extra_params->text_field.has_border;
       break;
     case WebThemeEngine::kPartMenuList:
       native_theme_extra_params->menu_list.has_border =
diff --git a/content/public/browser/navigation_type.h b/content/public/browser/navigation_type.h
index 242101b..bc449ff 100644
--- a/content/public/browser/navigation_type.h
+++ b/content/public/browser/navigation_type.h
@@ -13,22 +13,20 @@
   // Unknown type.
   NAVIGATION_TYPE_UNKNOWN,
 
-  // A new page was navigated to in the main frame. This covers all cases where
+  // A new entry was navigated to in the main frame. This covers all cases where
   // the main frame navigated and a new navigation entry was created. This means
-  // cases like navigations to a hash on the same page are NEW_PAGE, not
-  // IN_PAGE. (Navigation entries created by subframe navigations are
-  // NEW_SUBFRAME.)
-  NAVIGATION_TYPE_NEW_PAGE,
+  // cases like navigations to a hash on the same document are NEW_ENTRY.
+  // (Navigation entries created by subframe navigations are NEW_SUBFRAME.)
+  NAVIGATION_TYPE_NEW_ENTRY,
 
-  // Renavigating to an existing navigation entry. This is the case for history
-  // navigation, reloads, and location.replace().
-  NAVIGATION_TYPE_EXISTING_PAGE,
+  // Navigating to an existing navigation entry. This is the case for session
+  // history navigations, reloads, and history.replaceState().
+  NAVIGATION_TYPE_EXISTING_ENTRY,
 
-  // The same page has been reloaded as a result of the user requesting
-  // navigation to that same page (like pressing Enter in the URL bar). This
-  // is not the same as an in-page navigation because we'll actually have a
-  // pending entry for the load, which is then meaningless.
-  NAVIGATION_TYPE_SAME_PAGE,
+  // The same entry has been reloaded as a result of the user requesting
+  // navigation to that same page (like pressing Enter in the URL bar). There
+  // will be a pending entry for the load, which is unused.
+  NAVIGATION_TYPE_SAME_ENTRY,
 
   // A new subframe was manually navigated by the user. We will create a new
   // NavigationEntry so they can go back to the previous subframe content
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index 78174b92..18e1363 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -125,9 +125,7 @@
     const url::Origin* initiator_origin,
     GURL* new_url) {}
 
-bool ContentRendererClient::IsPrefetchOnly(
-    RenderFrame* render_frame,
-    const blink::WebURLRequest& request) {
+bool ContentRendererClient::IsPrefetchOnly(RenderFrame* render_frame) {
   return false;
 }
 
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index 7006cdc..a4695ba 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -224,10 +224,9 @@
                                const url::Origin* initiator_origin,
                                GURL* new_url);
 
-  // Returns true if the request is associated with a document that is in
-  // ""prefetch only" mode, and will not be rendered.
-  virtual bool IsPrefetchOnly(RenderFrame* render_frame,
-                              const blink::WebURLRequest& request);
+  // Returns true if the render frame is used for NoStatePrefetch and will not
+  // be rendered.
+  virtual bool IsPrefetchOnly(RenderFrame* render_frame);
 
   // See blink::Platform.
   virtual uint64_t VisitedLinkHash(const char* canonical_url, size_t length);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 8d9b4417..f17e769 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4530,7 +4530,7 @@
   url_request_extra_data->set_is_main_frame(IsMainFrame());
   url_request_extra_data->set_transition_type(transition_type);
   bool is_for_no_state_prefetch =
-      GetContentClient()->renderer()->IsPrefetchOnly(this, request);
+      GetContentClient()->renderer()->IsPrefetchOnly(this);
   url_request_extra_data->set_is_for_no_state_prefetch(
       is_for_no_state_prefetch);
   url_request_extra_data->set_frame_request_blocker(frame_request_blocker_);
diff --git a/content/test/data/forms/form_controls_browsertest_input.png b/content/test/data/forms/form_controls_browsertest_input.png
new file mode 100644
index 0000000..677bdaf
--- /dev/null
+++ b/content/test/data/forms/form_controls_browsertest_input.png
Binary files differ
diff --git a/content/test/data/forms/form_controls_browsertest_input_android.png b/content/test/data/forms/form_controls_browsertest_input_android.png
new file mode 100644
index 0000000..77bdeae6
--- /dev/null
+++ b/content/test/data/forms/form_controls_browsertest_input_android.png
Binary files differ
diff --git a/content/test/data/forms/form_controls_browsertest_input_mac.png b/content/test/data/forms/form_controls_browsertest_input_mac.png
new file mode 100644
index 0000000..a58c8f14
--- /dev/null
+++ b/content/test/data/forms/form_controls_browsertest_input_mac.png
Binary files differ
diff --git a/content/test/data/forms/form_controls_browsertest_input_win.png b/content/test/data/forms/form_controls_browsertest_input_win.png
new file mode 100644
index 0000000..a58c8f14
--- /dev/null
+++ b/content/test/data/forms/form_controls_browsertest_input_win.png
Binary files differ
diff --git a/content/test/gpu/unexpected_pass_finder.py b/content/test/gpu/unexpected_pass_finder.py
index ba55ad3..d17825b 100755
--- a/content/test/gpu/unexpected_pass_finder.py
+++ b/content/test/gpu/unexpected_pass_finder.py
@@ -153,20 +153,8 @@
   logging.getLogger().setLevel(level)
 
 
-def WarnUserOfIncompleteRollout():
-  response = raw_input('WARNING: This script relies on data from ResultDB, '
-                       'which is not enabled on all builders yet. As such, '
-                       'results from this script should not be trusted yet. '
-                       'Do you want to continue? y/N ')
-  if response.lower() != 'y':
-    sys.exit(0)
-
-
 def main():
   args = ParseArgs()
-  # TODO(crbug.com/1108016): Remove this warning once ResultDB is enabled on all
-  # builders and there is enough data for the results to be trusted.
-  WarnUserOfIncompleteRollout()
   test_expectation_map = expectations.CreateTestExpectationMap(
       args.expectation_file, args.tests)
   ci_builders = builders.GetCiBuilders(
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
index b4126ee..3c22b2f2 100644
--- a/device/bluetooth/bluetooth_device.h
+++ b/device/bluetooth/bluetooth_device.h
@@ -605,12 +605,8 @@
 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
   // Set the remaining battery of the device to show in the UI. This value must
   // be between 0 and 100, inclusive.
-  // TODO(http://b/160905785): Battery percentage is populated by
-  // ash::HfpBatteryListener, ash::HidBatteryListener, and
-  // device::BluetoothAdapterBlueZ. When Battery information is entirely
-  // consolidated in BlueZ's Battery API, only device::BluetoothAdapterBlueZ
-  // should have control over this field with the value originating from a
-  // single source, the BlueZ Battery API..
+  // Only device::BluetoothAdapterBlueZ has control over this field with the
+  // value originating from a single source, the BlueZ Battery API.
   void SetBatteryPercentage(base::Optional<uint8_t> battery_percentage);
 
   // Returns the remaining battery for the device.
diff --git a/device/fido/cable/v2_test_util.cc b/device/fido/cable/v2_test_util.cc
index ffdcbc8b..c4731c7 100644
--- a/device/fido/cable/v2_test_util.cc
+++ b/device/fido/cable/v2_test_util.cc
@@ -170,7 +170,7 @@
     void SendMessage(network::mojom::WebSocketMessageType type,
                      uint64_t length) override {
       if (!peer_ || !peer_->connected_) {
-        pending_messages_.emplace_back(std::make_tuple(type, length));
+        pending_messages_.emplace_back(std::make_pair(type, length));
       } else {
         peer_->client_receiver_->OnDataFrame(/*final=*/true, type, length);
       }
diff --git a/device/fido/cros/authenticator.cc b/device/fido/cros/authenticator.cc
index ef44552d..432ae70 100644
--- a/device/fido/cros/authenticator.cc
+++ b/device/fido/cros/authenticator.cc
@@ -106,6 +106,9 @@
     const std::vector<uint8_t>& id = descriptor.id();
     req.add_excluded_credential_id(std::string(id.begin(), id.end()));
   }
+  if (request.app_id) {
+    req.set_app_id_exclude(*request.app_id);
+  }
 
   dbus::MethodCall method_call(u2f::kU2FInterface, u2f::kU2FMakeCredential);
   dbus::MessageWriter writer(&method_call);
@@ -204,6 +207,9 @@
           ? u2f::VERIFICATION_USER_PRESENCE
           : u2f::VERIFICATION_USER_VERIFICATION);
   req.set_rp_id(request.rp_id);
+  if (request.app_id) {
+    req.set_app_id(*request.app_id);
+  }
   req.set_client_data_hash(std::string(request.client_data_hash.begin(),
                                        request.client_data_hash.end()));
   DCHECK(generate_request_id_callback_);
@@ -297,6 +303,10 @@
 
   u2f::HasCredentialsRequest req;
   req.set_rp_id(request.rp_id);
+  if (request.app_id) {
+    req.set_app_id(*request.app_id);
+  }
+
   for (const PublicKeyCredentialDescriptor& descriptor : request.allow_list) {
     const std::vector<uint8_t>& id = descriptor.id();
     req.add_credential_id(std::string(id.begin(), id.end()));
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h
index 9763a6d..2409fab2 100644
--- a/extensions/browser/extension_event_histogram_value.h
+++ b/extensions/browser/extension_event_histogram_value.h
@@ -488,6 +488,8 @@
   ACCESSIBILITY_PRIVATE_ON_POINT_SCAN_SET = 466,
   ACCESSIBILITY_PRIVATE_ON_SELECT_TO_SPEAK_PANEL_ACTION = 467,
   FILE_MANAGER_PRIVATE_ON_TABLET_MODE_CHANGED = 468,
+  VIRTUAL_KEYBOARD_PRIVATE_ON_CLIPBOARD_HISTORY_CHANGED = 469,
+  VIRTUAL_KEYBOARD_PRIVATE_ON_CLIPBOARD_ITEM_UPDATED = 470,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/common/api/virtual_keyboard_private.json b/extensions/common/api/virtual_keyboard_private.json
index 36bc2740..76efa96 100644
--- a/extensions/common/api/virtual_keyboard_private.json
+++ b/extensions/common/api/virtual_keyboard_private.json
@@ -431,7 +431,7 @@
       },
       {
         "name": "onClipboardHistoryChanged",
-        "type": "funciton",
+        "type": "function",
         "description": "Fired when the list of items in the clipboard history changes.",
         "parameters": [
           {
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index b0b7234..d271c4e 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -215,6 +215,8 @@
     return nullptr;
   }
 
+  extension->guid_ = base::GUID::GenerateRandomV4();
+
   return extension;
 }
 
@@ -398,6 +400,16 @@
   manifest_data_[key] = std::move(data);
 }
 
+void Extension::SetGUID(const ExtensionGuid& guid) {
+  guid_ = base::GUID::ParseLowercase(guid);
+  DCHECK(guid_.is_valid());
+}
+
+const ExtensionGuid& Extension::guid() const {
+  DCHECK(guid_.is_valid());
+  return guid_.AsLowercaseString();
+}
+
 Manifest::Location Extension::location() const {
   return manifest_->location();
 }
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index 6e7b2c2..3c9d8c5 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -13,11 +13,13 @@
 
 #include "base/auto_reset.h"
 #include "base/files/file_path.h"
+#include "base/guid.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
 #include "base/version.h"
 #include "extensions/buildflags/buildflags.h"
+#include "extensions/common/extension_guid.h"
 #include "extensions/common/extension_id.h"
 #include "extensions/common/extension_resource.h"
 #include "extensions/common/hashed_extension_id.h"
@@ -254,6 +256,11 @@
   void SetManifestData(const std::string& key,
                        std::unique_ptr<ManifestData> data);
 
+  // Sets the GUID for this extension. Note: this should *only* be used when
+  // duplicating an existing extension; otherwise, the GUID will be
+  // appropriately set during creation (ensuring uniqueness).
+  void SetGUID(const ExtensionGuid& guid);
+
   // Accessors:
 
   const base::FilePath& path() const { return path_; }
@@ -262,6 +269,7 @@
   Manifest::Location location() const;
   const ExtensionId& id() const;
   const HashedExtensionId& hashed_id() const;
+  const ExtensionGuid& guid() const;
   const base::Version& version() const { return version_; }
   const std::string& version_name() const { return version_name_; }
   std::string VersionString() const;
@@ -466,6 +474,10 @@
   // The flags that were passed to InitFromValue.
   int creation_flags_;
 
+  // A dynamic ID that can be used when referencing extension resources via URL
+  // instead of an extension ID.
+  base::GUID guid_;
+
   DISALLOW_COPY_AND_ASSIGN(Extension);
 };
 
diff --git a/extensions/common/extension_guid.h b/extensions/common/extension_guid.h
new file mode 100644
index 0000000..f43d13f
--- /dev/null
+++ b/extensions/common/extension_guid.h
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_COMMON_EXTENSION_GUID_H_
+#define EXTENSIONS_COMMON_EXTENSION_GUID_H_
+
+#include <string>
+
+namespace extensions {
+
+// If valid, uniquely identifies an Extension using a generated GUID.
+using ExtensionGuid = std::string;
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_COMMON_EXTENSION_GUID_H_
diff --git a/extensions/common/extension_messages.cc b/extensions/common/extension_messages.cc
index d62a27bf..26ba3a0 100644
--- a/extensions/common/extension_messages.cc
+++ b/extensions/common/extension_messages.cc
@@ -79,7 +79,8 @@
           extension->permissions_data()->UsesDefaultPolicyHostRestrictions()),
       id(extension->id()),
       worker_activation_sequence(worker_activation_sequence),
-      creation_flags(extension->creation_flags()) {
+      creation_flags(extension->creation_flags()),
+      guid(extension->guid()) {
   if (include_tab_permissions) {
     for (const auto& pair :
          extension->permissions_data()->tab_specific_permissions()) {
@@ -117,6 +118,7 @@
       permissions_data->UpdateTabSpecificPermissions(
           pair.first, *pair.second.ToPermissionSet());
     }
+    extension->SetGUID(guid);
   }
   return extension;
 }
@@ -332,6 +334,7 @@
   WriteParam(m, p.policy_allowed_hosts);
   WriteParam(m, p.uses_default_policy_blocked_allowed_hosts);
   WriteParam(m, p.worker_activation_sequence);
+  WriteParam(m, p.guid);
 }
 
 bool ParamTraits<ExtensionMsg_Loaded_Params>::Read(const base::Pickle* m,
@@ -347,7 +350,8 @@
          ReadParam(m, iter, &p->policy_blocked_hosts) &&
          ReadParam(m, iter, &p->policy_allowed_hosts) &&
          ReadParam(m, iter, &p->uses_default_policy_blocked_allowed_hosts) &&
-         ReadParam(m, iter, &p->worker_activation_sequence);
+         ReadParam(m, iter, &p->worker_activation_sequence) &&
+         ReadParam(m, iter, &p->guid);
 }
 
 void ParamTraits<ExtensionMsg_Loaded_Params>::Log(const param_type& p,
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h
index 9164cd1..1038a65f 100644
--- a/extensions/common/extension_messages.h
+++ b/extensions/common/extension_messages.h
@@ -30,6 +30,7 @@
 #include "extensions/common/draggable_region.h"
 #include "extensions/common/event_filtering_info.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_guid.h"
 #include "extensions/common/extensions_client.h"
 #include "extensions/common/host_id.h"
 #include "extensions/common/message_bundle.h"
@@ -406,6 +407,9 @@
   // Send creation flags so extension is initialized identically.
   int creation_flags;
 
+  // Reuse the extension guid when creating the extension in the renderer.
+  extensions::ExtensionGuid guid;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ExtensionMsg_Loaded_Params);
 };
diff --git a/extensions/common/extension_messages_unittest.cc b/extensions/common/extension_messages_unittest.cc
index 6347f78..548eb84 100644
--- a/extensions/common/extension_messages_unittest.cc
+++ b/extensions/common/extension_messages_unittest.cc
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "extensions/common/extension_messages.h"
+
 #include "components/crx_file/id_util.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
-#include "extensions/common/extension_messages.h"
 #include "extensions/common/manifest_handlers/permissions_parser.h"
 #include "extensions/common/permissions/extensions_api_permissions.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -83,6 +84,7 @@
 
   ExtensionMsg_Loaded_Params params_in(extension.get(), true, base::nullopt);
   EXPECT_EQ(extension->id(), params_in.id);
+  EXPECT_EQ(extension->guid(), params_in.guid);
 
   {
     // First, test just converting back to an extension.
@@ -122,6 +124,9 @@
     EXPECT_TRUE(error.empty());
     ASSERT_TRUE(extension_out);
     CompareExtension(*extension, *extension_out);
+
+    // Check for guid in converted extension.
+    EXPECT_EQ(extension->guid(), extension_out->guid());
   }
 }
 
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index 990d80d..f7d5506 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -107,7 +107,6 @@
 const char kOAuth2ClientId[] = "oauth2.client_id";
 const char kOAuth2Scopes[] = "oauth2.scopes";
 const char kOfflineEnabled[] = "offline_enabled";
-const char kOmnibox[] = "omnibox";
 const char kOmniboxKeyword[] = "omnibox.keyword";
 const char kOptionalPermissions[] = "optional_permissions";
 const char kOptionsPage[] = "options_page";
@@ -544,8 +543,8 @@
     "Invalid value for 'oauth2.scopes'.";
 const char kInvalidOfflineEnabled[] =
     "Invalid value for 'offline_enabled'.";
-const char kInvalidOmniboxKeyword[] =
-    "Invalid value for 'omnibox.keyword'.";
+const char kEmptyOmniboxKeyword[] =
+    "Invalid value for 'omnibox.keyword'. It must be non-empty.";
 const char kInvalidOptionsPage[] = "Invalid value for '*'.";
 const char kInvalidOptionsPageExpectUrlInPackage[] =
     "Invalid value for 'options_page'.  Value must be a relative path.";
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index 0a93f7c..c5892d78 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -111,7 +111,6 @@
 extern const char kOAuth2ClientId[];
 extern const char kOAuth2Scopes[];
 extern const char kOfflineEnabled[];
-extern const char kOmnibox[];
 extern const char kOmniboxKeyword[];
 extern const char kOptionalPermissions[];
 extern const char kOptionsPage[];
@@ -396,7 +395,7 @@
 extern const char kInvalidOAuth2ClientId[];
 extern const char kInvalidOAuth2Scopes[];
 extern const char kInvalidOfflineEnabled[];
-extern const char kInvalidOmniboxKeyword[];
+extern const char kEmptyOmniboxKeyword[];
 extern const char kInvalidOptionsUIChromeStyle[];
 extern const char kInvalidOptionsUIOpenInTab[];
 extern const char kInvalidOptionsPage[];
diff --git a/extensions/renderer/console.cc b/extensions/renderer/console.cc
index 2760947c..99a874f 100644
--- a/extensions/renderer/console.cc
+++ b/extensions/renderer/console.cc
@@ -96,8 +96,8 @@
     for (const auto& method : methods) {
       v8::Local<v8::FunctionTemplate> function = v8::FunctionTemplate::New(
           isolate, BoundLogMethodCallback,
-          v8::Integer::New(isolate, static_cast<int>(method.level)));
-      function->RemovePrototype();
+          v8::Integer::New(isolate, static_cast<int>(method.level)),
+          v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow);
       templ->Set(gin::StringToSymbol(isolate, method.name), function);
     }
     data->SetObjectTemplate(&kWrapperInfo, templ);
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc
index 6c6b722e8..404a43c 100644
--- a/extensions/renderer/module_system.cc
+++ b/extensions/renderer/module_system.cc
@@ -730,9 +730,8 @@
   v8::Local<v8::Object> exports = v8::Object::New(GetIsolate());
 
   v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(
-      GetIsolate(),
-      &SetExportsProperty);
-  tmpl->RemovePrototype();
+      GetIsolate(), &SetExportsProperty, v8::Local<v8::Value>(),
+      v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow);
   v8::Local<v8::String> v8_key;
   if (!ToV8String(GetIsolate(), "$set", &v8_key)) {
     NOTREACHED();
diff --git a/extensions/renderer/object_backed_native_handler.cc b/extensions/renderer/object_backed_native_handler.cc
index f9f5cb3..c403df5 100644
--- a/extensions/renderer/object_backed_native_handler.cc
+++ b/extensions/renderer/object_backed_native_handler.cc
@@ -144,9 +144,9 @@
       << feature_name;
   SetPrivate(data, kFeatureName,
              v8_helpers::ToV8StringUnsafe(isolate, feature_name));
-  v8::Local<v8::FunctionTemplate> function_template =
-      v8::FunctionTemplate::New(isolate, Router, data);
-  function_template->RemovePrototype();
+  v8::Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(
+      isolate, Router, data, v8::Local<v8::Signature>(), 0,
+      v8::ConstructorBehavior::kThrow);
   v8::Local<v8::ObjectTemplate>::New(isolate, object_template_)
       ->Set(isolate, name.c_str(), function_template);
   router_data_.Append(data);
diff --git a/google_apis/gaia/gaia_constants.cc b/google_apis/gaia/gaia_constants.cc
index 29218a73..4ee1585 100644
--- a/google_apis/gaia/gaia_constants.cc
+++ b/google_apis/gaia/gaia_constants.cc
@@ -107,4 +107,8 @@
 
 // Used as an Invalid refresh token.
 const char kInvalidRefreshToken[] = "invalid_refresh_token";
+
+// Name of the Google authentication cookie.
+const char kGaiaSigninCookieName[] = "SAPISID";
+
 }  // namespace GaiaConstants
diff --git a/google_apis/gaia/gaia_constants.h b/google_apis/gaia/gaia_constants.h
index 6563f31..4e1ecf1 100644
--- a/google_apis/gaia/gaia_constants.h
+++ b/google_apis/gaia/gaia_constants.h
@@ -58,6 +58,9 @@
 
 // Refresh token that is guaranteed to be invalid.
 extern const char kInvalidRefreshToken[];
+
+// Name of the Google authentication cookie.
+extern const char kGaiaSigninCookieName[];
 }  // namespace GaiaConstants
 
 #endif  // GOOGLE_APIS_GAIA_GAIA_CONSTANTS_H_
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 1eb1bd9..e157ed56 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -13076,61 +13076,6 @@
       }
     }
     builders {
-      name: "UBSanVptr Linux"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:32"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium.clang\",\"perf_dashboard_machine_group\":\"ChromiumClang\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 50400
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.gtests_local"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-      }
-    }
-    builders {
       name: "VR Linux"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index 849986f..4674acfc 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -4325,10 +4325,6 @@
   refs: "regexp:refs/heads/master"
   manifest_name: "REVISION"
   builders {
-    name: "buildbucket/luci.chromium.ci/UBSanVptr Linux"
-    short_name: "usn"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/ToTLinux"
     category: "ToT Linux"
     short_name: "rel"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg
index f5dfeb64..2abad2a4 100644
--- a/infra/config/generated/luci-scheduler.cfg
+++ b/infra/config/generated/luci-scheduler.cfg
@@ -3149,16 +3149,6 @@
   }
 }
 job {
-  id: "UBSanVptr Linux"
-  realm: "ci"
-  acl_sets: "ci"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "UBSanVptr Linux"
-  }
-}
-job {
   id: "VR Linux"
   realm: "ci"
   acl_sets: "ci"
@@ -7013,7 +7003,6 @@
   triggers: "ToTiOSDevice"
   triggers: "UBSan Release"
   triggers: "UBSan vptr Release"
-  triggers: "UBSanVptr Linux"
   triggers: "VR Linux"
   triggers: "WebKit Linux ASAN"
   triggers: "WebKit Linux Leak"
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index b7112793..3698c2c 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -2027,14 +2027,6 @@
 )
 
 ci.clang_builder(
-    name = "UBSanVptr Linux",
-    console_view_entry = consoles.console_view_entry(
-        short_name = "usn",
-    ),
-    goma_backend = goma.backend.RBE_PROD,
-)
-
-ci.clang_builder(
     name = "ToTWindowsCoverage",
     console_view_entry = consoles.console_view_entry(
         category = "ToT Code Coverage",
diff --git a/ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.mm b/ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.mm
index 6fabc45..739d6e1e 100644
--- a/ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.mm
+++ b/ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.mm
@@ -74,17 +74,17 @@
       std::make_unique<invalidation::FCMInvalidationService>(
           identity_provider.get(),
           base::BindRepeating(
-              &syncer::FCMNetworkHandler::Create,
+              &invalidation::FCMNetworkHandler::Create,
               IOSChromeGCMProfileServiceFactory::GetForBrowserState(
                   browser_state)
                   ->driver(),
               IOSChromeInstanceIDProfileServiceFactory::GetForBrowserState(
                   browser_state)
                   ->driver()),
-          base::BindRepeating(&syncer::PerUserTopicSubscriptionManager::Create,
-                              identity_provider.get(),
-                              browser_state->GetPrefs(),
-                              browser_state->GetURLLoaderFactory()),
+          base::BindRepeating(
+              &invalidation::PerUserTopicSubscriptionManager::Create,
+              identity_provider.get(), browser_state->GetPrefs(),
+              browser_state->GetURLLoaderFactory()),
           IOSChromeInstanceIDProfileServiceFactory::GetForBrowserState(
               browser_state)
               ->driver(),
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 801b133..2336daf 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -168,6 +168,8 @@
   FirstRun::RegisterProfilePrefs(registry);
   FontSizeTabHelper::RegisterBrowserStatePrefs(registry);
   HostContentSettingsMap::RegisterProfilePrefs(registry);
+  invalidation::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry);
+  invalidation::PerUserTopicSubscriptionManager::RegisterProfilePrefs(registry);
   ios::NotificationPromo::RegisterProfilePrefs(registry);
   language::LanguagePrefs::RegisterProfilePrefs(registry);
   metrics::RegisterDemographicsProfilePrefs(registry);
@@ -188,8 +190,6 @@
   safe_browsing::RegisterProfilePrefs(registry);
   sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry);
   syncer::DeviceInfoPrefs::RegisterProfilePrefs(registry);
-  syncer::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry);
-  syncer::PerUserTopicSubscriptionManager::RegisterProfilePrefs(registry);
   syncer::SyncPrefs::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
   translate::TranslatePrefs::RegisterProfilePrefs(registry);
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h
index 9f8da56..e87a1f4 100644
--- a/ios/chrome/browser/signin/authentication_service.h
+++ b/ios/chrome/browser/signin/authentication_service.h
@@ -196,7 +196,7 @@
   void OnEndBatchOfRefreshTokenStateChanges() override;
 
   // ChromeIdentityServiceObserver implementation.
-  void OnIdentityListChanged() override;
+  void OnIdentityListChanged(bool keychainReload) override;
   void OnAccessTokenRefreshFailed(ChromeIdentity* identity,
                                   NSDictionary* user_info) override;
   void OnChromeIdentityServiceWillBeDestroyed() override;
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm
index 4b439ca2..71704ce2 100644
--- a/ios/chrome/browser/signin/authentication_service.mm
+++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -435,7 +435,7 @@
   StoreKnownAccountsWhileInForeground();
 }
 
-void AuthenticationService::OnIdentityListChanged() {
+void AuthenticationService::OnIdentityListChanged(bool keychainReload) {
   // The list of identities may change while in an authorized call. Signing out
   // the authenticated user at this time may lead to crashes (e.g.
   // http://crbug.com/398431 ).
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm
index 9a69ab5..f54a0769 100644
--- a/ios/chrome/browser/signin/authentication_service_unittest.mm
+++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -126,8 +126,8 @@
     authentication_service()->OnAccessTokenRefreshFailed(identity, user_info);
   }
 
-  void FireIdentityListChanged() {
-    authentication_service()->OnIdentityListChanged();
+  void FireIdentityListChanged(bool keychainReload) {
+    authentication_service()->OnIdentityListChanged(keychainReload);
   }
 
   void SetCachedMDMInfo(ChromeIdentity* identity, NSDictionary* user_info) {
@@ -313,7 +313,7 @@
   authentication_service()->SignIn(identity(0));
 
   identity_service()->AddIdentities(@[ @"foo3" ]);
-  FireIdentityListChanged();
+  FireIdentityListChanged(true);
   base::RunLoop().RunUntilIdle();
 
   // If an account is added while the application is in foreground, then the
@@ -337,7 +337,7 @@
   authentication_service()->SignIn(identity(0));
 
   identity_service()->AddIdentities(@[ @"foo3" ]);
-  FireIdentityListChanged();
+  FireIdentityListChanged(true);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(
       authentication_service()->HaveAccountsChangedWhileInBackground());
@@ -355,7 +355,7 @@
   authentication_service()->SignIn(identity(0));
 
   identity_service()->AddIdentities(@[ @"foo3" ]);
-  FireIdentityListChanged();
+  FireIdentityListChanged(true);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(
       authentication_service()->HaveAccountsChangedWhileInBackground());
@@ -364,7 +364,7 @@
   // background.
   FireApplicationDidEnterBackground();
   identity_service()->AddIdentities(@[ @"foo4" ]);
-  FireIdentityListChanged();
+  FireIdentityListChanged(true);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(authentication_service()->HaveAccountsChangedWhileInBackground());
 
@@ -379,7 +379,7 @@
   authentication_service()->SignIn(identity(0));
 
   identity_service()->AddIdentities(@[ @"foo3" ]);
-  FireIdentityListChanged();
+  FireIdentityListChanged(true);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(
       authentication_service()->HaveAccountsChangedWhileInBackground());
diff --git a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h
index 80244b6e..024253b 100644
--- a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h
+++ b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h
@@ -31,7 +31,7 @@
 
  private:
   // ios::ChromeIdentityService::Observer implementation.
-  void OnIdentityListChanged() override;
+  void OnIdentityListChanged(bool keychainReload) override;
   void OnAccessTokenRefreshFailed(ChromeIdentity* identity,
                                   NSDictionary* user_info) override;
   void OnProfileUpdate(ChromeIdentity* identity) override;
diff --git a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.mm b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.mm
index eb34907..1b9cb47 100644
--- a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.mm
+++ b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge.mm
@@ -21,7 +21,8 @@
 
 ChromeIdentityServiceObserverBridge::~ChromeIdentityServiceObserverBridge() {}
 
-void ChromeIdentityServiceObserverBridge::OnIdentityListChanged() {
+void ChromeIdentityServiceObserverBridge::OnIdentityListChanged(
+    bool keychainReload) {
   if ([observer_ respondsToSelector:@selector(identityListChanged)])
     [observer_ identityListChanged];
 }
diff --git a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge_unittest.mm b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge_unittest.mm
index 6956784d5..f0ba2c0 100644
--- a/ios/chrome/browser/signin/chrome_identity_service_observer_bridge_unittest.mm
+++ b/ios/chrome/browser/signin/chrome_identity_service_observer_bridge_unittest.mm
@@ -97,7 +97,7 @@
 // Tests that |onIdentityListChanged| is forwarded.
 TEST_F(ChromeIdentityServiceObserverBridgeTest, onIdentityListChanged) {
   ASSERT_FALSE(GetTestObserver().onIdentityListChangedCalled);
-  GetObserverBridge()->OnIdentityListChanged();
+  GetObserverBridge()->OnIdentityListChanged(false);
   EXPECT_TRUE(GetTestObserver().onIdentityListChangedCalled);
   EXPECT_FALSE(GetTestObserver().onAccessTokenRefreshFailedCalled);
   EXPECT_FALSE(GetTestObserver().onProfileUpdateCalled);
diff --git a/ios/chrome/browser/ui/browser_view/hider/browser_view_hider_view_controller.mm b/ios/chrome/browser/ui/browser_view/hider/browser_view_hider_view_controller.mm
index 97c58d5..61c6898 100644
--- a/ios/chrome/browser/ui/browser_view/hider/browser_view_hider_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/hider/browser_view_hider_view_controller.mm
@@ -57,6 +57,7 @@
   UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc]
       initWithTarget:panGestureHandler
               action:@selector(handlePanGesture:)];
+  panGestureRecognizer.delegate = panGestureHandler;
   panGestureRecognizer.maximumNumberOfTouches = 1;
   [self.view addGestureRecognizer:panGestureRecognizer];
 
diff --git a/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.h b/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.h
index dc5343de3..0e057655 100644
--- a/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.h
+++ b/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.h
@@ -23,7 +23,9 @@
 // to a revealed state (and vice-versa) if the gesture's translation and
 // velocity are enough to trigger such transition.
 @interface ViewRevealingVerticalPanHandler
-    : NSObject <CRWWebViewScrollViewProxyObserver, UIScrollViewDelegate>
+    : NSObject <CRWWebViewScrollViewProxyObserver,
+                UIGestureRecognizerDelegate,
+                UIScrollViewDelegate>
 
 // |peekedHeight| is the height of the view when peeked (partially revealed).
 // |revealedCoverHeight| is the height of the cover view that remains visible
diff --git a/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.mm b/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.mm
index c8c741c5..91a4e3c 100644
--- a/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.mm
+++ b/ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.mm
@@ -65,6 +65,10 @@
 // -scrollViewDidScroll:.
 @property(nonatomic, assign) CGPoint lastScrollOffset;
 
+// Holds the gesture recognizer that is currently in progess. Any other
+// gestures received while one is active will be ignored.
+@property(nonatomic, weak) UIGestureRecognizer* currentRecognizer;
+
 @end
 
 @implementation ViewRevealingVerticalPanHandler
@@ -103,6 +107,9 @@
   } else if (gesture.state == UIGestureRecognizerStateEnded) {
     CGFloat velocityY = [gesture velocityInView:gesture.view.superview].y;
     [self panGestureEndedWithTranslation:translationY velocity:velocityY];
+    self.currentRecognizer = nil;
+  } else if (gesture.state == UIGestureRecognizerStateCancelled) {
+    self.currentRecognizer = nil;
   }
 }
 
@@ -431,6 +438,10 @@
 
 - (void)panHandlerScrollViewWillBeginDragging:
     (PanHandlerScrollView*)scrollView {
+  if (self.currentRecognizer &&
+      self.currentRecognizer != scrollView.panGestureRecognizer) {
+    return;
+  }
   switch (self.currentState) {
     case ViewRevealState::Hidden: {
       // The transition out of hidden state can only start if the scroll view
@@ -449,14 +460,19 @@
       // be able to be scrolled.
       NOTREACHED();
   }
+  self.currentRecognizer = scrollView.panGestureRecognizer;
   [self panGestureBegan];
   self.lastScrollOffset = scrollView.contentOffset;
 }
 
 - (void)panHandlerScrollViewDidScroll:(PanHandlerScrollView*)scrollView {
-  // These delegate methods are approximating the pan gesture handling from
-  // above, so only change things if the user is actively scrolling.
-  if (!scrollView.isDragging) {
+  // Early return if there is no current recognizer or one that does not match
+  // this scroll view's recognizer. The first can happen when the scroll view
+  // scrolls after the user lifts their finger. This should not be handled as
+  // these methods are only approximating the actual pan gesture handling from
+  // above. The second can happen if the user scrolls and uses one of the pan
+  // gestures simultaneously.
+  if (self.currentRecognizer != scrollView.panGestureRecognizer) {
     return;
   }
   UIPanGestureRecognizer* gesture = scrollView.panGestureRecognizer;
@@ -481,6 +497,16 @@
                                withVelocity:(CGPoint)velocity
                         targetContentOffset:
                             (inout CGPoint*)targetContentOffset {
+  // Early return if there is no current recognizer or one that does not match
+  // this scroll view's recognizer. The first can happen when the scroll view
+  // scrolls after the user lifts their finger. This should not be handled as
+  // these methods are only approximating the actual pan gesture handling from
+  // above. The second can happen if the user scrolls and uses one of the pan
+  // gestures simultaneously.
+  if (self.currentRecognizer != scrollView.panGestureRecognizer) {
+    return;
+  }
+  self.currentRecognizer = nil;
   if (self.currentState == ViewRevealState::Hidden &&
       self.animator.state != UIViewAnimatingStateActive) {
     return;
@@ -497,4 +523,14 @@
   [self panGestureEndedWithTranslation:translationY velocity:velocityY];
 }
 
+#pragma mark - UIGestureRecognizerDelegate
+
+- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
+  if (self.currentRecognizer) {
+    return NO;
+  }
+  self.currentRecognizer = gestureRecognizer;
+  return YES;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler.mm b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
index 12e3b520..76947fd 100644
--- a/ios/chrome/browser/ui/main/browser_view_wrangler.mm
+++ b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
@@ -166,24 +166,8 @@
 
   [self dispatchToEndpointsForBrowser:_mainBrowser.get()];
 
-  std::string sessionID = base::SysNSStringToUTF8(self.sessionID);
-  SnapshotBrowserAgent::FromBrowser(_mainBrowser.get())
-      ->SetSessionID(sessionID);
+  [self setSessionIDForBrowser:_mainBrowser.get() restoreSession:YES];
 
-  // If the OS doesn't support multiple scenes, use the previous run scene ID
-  // for the session restoration.
-  NSString* restoreSessionID = self.sessionID;
-  if (_sceneState.appState.previousSingleWindowSessionID) {
-    restoreSessionID = _sceneState.appState.previousSingleWindowSessionID;
-  }
-  SessionRestorationBrowserAgent* restorationAgent =
-      SessionRestorationBrowserAgent::FromBrowser(_mainBrowser.get());
-  restorationAgent->SetSessionID(base::SysNSStringToUTF8(restoreSessionID));
-  restorationAgent->RestoreSession();
-  restorationAgent->SetSessionID(sessionID);
-  if (base::SysNSStringToUTF8(restoreSessionID) != sessionID) {
-    restorationAgent->SaveSession(true);
-  }
   breakpad::MonitorTabStateForWebStateList(_mainBrowser->GetWebStateList());
   // Follow loaded URLs in the main tab model to send those in case of
   // crashes.
@@ -381,14 +365,9 @@
       BrowserListFactory::GetForBrowserState(browser->GetBrowserState());
   browserList->AddIncognitoBrowser(browser.get());
   [self dispatchToEndpointsForBrowser:browser.get()];
-  std::string sessionID = base::SysNSStringToUTF8(self.sessionID);
-  SnapshotBrowserAgent::FromBrowser(browser.get())->SetSessionID(sessionID);
-  SessionRestorationBrowserAgent::FromBrowser(browser.get())
-      ->SetSessionID(sessionID);
-  if (restorePersistedState) {
-    SessionRestorationBrowserAgent::FromBrowser(browser.get())
-        ->RestoreSession();
-  }
+
+  [self setSessionIDForBrowser:browser.get()
+                restoreSession:restorePersistedState];
 
   // Associate the same SceneState with the new OTR browser as is associated
   // with the main browser.
@@ -430,4 +409,55 @@
                            forProtocol:@protocol(BrowsingDataCommands)];
 }
 
+- (void)setSessionIDForBrowser:(Browser*)browser
+                restoreSession:(BOOL)restoreSession {
+  SnapshotBrowserAgent::FromBrowser(browser)->SetSessionID(
+      base::SysNSStringToUTF8(self.sessionID));
+
+  SessionRestorationBrowserAgent* restorationAgent =
+      SessionRestorationBrowserAgent::FromBrowser(browser);
+
+  // crbug.com/1153606: when the app is distributed with multi-window enabled,
+  // the "swipe gesture" is sometimes interpreted as a "close window" gesture
+  // by iOS (reproduce easily if the user launch app, swipe it away in a loop).
+  // On the next start after iOS has decided the gesture is "close window", the
+  // session identifier will be reset to a different value.
+  //
+  // For device that support multiple windows (recent iPads running iOS 13+),
+  // the user has the option to restore recently closed windows (presented by
+  // iOS when user ask to see all windows). For other devices however they have
+  // no option to re-open the closed window and lose their data.
+  //
+  // To workaround this behaviour, the session identifier is saved, and on each
+  // run, if the device does not support multi-window, compared to the current
+  // session identifier. If there is a mismatch, load the session using the old
+  // identifier (which is used to construct path to Chrome's session data), and
+  // immediately save it with the new identifier.
+  //
+  // TODO(crbug.com/1165798): clean up this by using fixed identifier when the
+  // device do no support multi-windows.
+  if (!IsMultipleScenesSupported() && restoreSession) {
+    NSString* previousSessionID =
+        _sceneState.appState.previousSingleWindowSessionID;
+    if (previousSessionID &&
+        ![self.sessionID isEqualToString:previousSessionID]) {
+      restorationAgent->SetSessionID(
+          base::SysNSStringToUTF8(previousSessionID));
+      restorationAgent->RestoreSession();
+
+      restorationAgent->SetSessionID(base::SysNSStringToUTF8(self.sessionID));
+      restorationAgent->SaveSession(true);
+
+      // Fallback to the normal codepath. It will set the session identifier
+      // in the SessionRestorationBrowserAgent. Since the session has been
+      // loaded already, skip this step by setting |restoreSession| to NO.
+      restoreSession = NO;
+    }
+  }
+
+  restorationAgent->SetSessionID(base::SysNSStringToUTF8(self.sessionID));
+  if (restoreSession)
+    restorationAgent->RestoreSession();
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/privacy/BUILD.gn b/ios/chrome/browser/ui/settings/privacy/BUILD.gn
index d3efc5f..5c41334 100644
--- a/ios/chrome/browser/ui/settings/privacy/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/privacy/BUILD.gn
@@ -24,6 +24,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browsing_data:feature_flags",
     "//ios/chrome/browser/main:public",
+    "//ios/chrome/browser/prefs:browser_prefs",
     "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/colors",
     "//ios/chrome/browser/ui/commands",
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm
index a177a3fb..4f491aa 100644
--- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm
@@ -19,6 +19,7 @@
 #include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #import "ios/chrome/browser/main/browser.h"
 #include "ios/chrome/browser/pref_names.h"
+#import "ios/chrome/browser/prefs/prefs_util.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h"
@@ -167,7 +168,10 @@
   [model addItem:[self handoffDetailItem]
       toSectionWithIdentifier:SectionIdentifierWebServices];
 
-  if (base::FeatureList::IsEnabled(kIncognitoAuthentication)) {
+  // Do not show the incognito authentication setting when Incongito mode is
+  // disabled.
+  if (base::FeatureList::IsEnabled(kIncognitoAuthentication) &&
+      !IsIncognitoModeDisabled(_browserState->GetPrefs())) {
     // Incognito authentication item.
     [model addItem:self.incognitoReauthItem
         toSectionWithIdentifier:SectionIdentifierIncognitoAuth];
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index 6401221..3c99c67 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -568,6 +568,7 @@
   UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc]
       initWithTarget:panGestureHandler
               action:@selector(handlePanGesture:)];
+  panGestureRecognizer.delegate = panGestureHandler;
   panGestureRecognizer.maximumNumberOfTouches = 1;
   [self.view addGestureRecognizer:panGestureRecognizer];
 
diff --git a/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm
index 953434237..f4381a9c1 100644
--- a/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/primary_toolbar_view_controller.mm
@@ -66,6 +66,7 @@
   UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc]
       initWithTarget:panGestureHandler
               action:@selector(handlePanGesture:)];
+  panGestureRecognizer.delegate = panGestureHandler;
   panGestureRecognizer.maximumNumberOfTouches = 1;
   [self.view addGestureRecognizer:panGestureRecognizer];
 
diff --git a/ios/chrome/test/wpt/OWNERS b/ios/chrome/test/wpt/OWNERS
new file mode 100644
index 0000000..0e69fc8
--- /dev/null
+++ b/ios/chrome/test/wpt/OWNERS
@@ -0,0 +1 @@
+ajuma@chromium.org
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
index fa1eeae..91e2d77 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
@@ -79,8 +79,15 @@
     virtual ~Observer() {}
 
     // Handles identity list changed events.
+    // Deprecated, see OnIdentityListChanged(bool).
     virtual void OnIdentityListChanged() {}
 
+    // Handles identity list changed events.
+    // |keychainReload| is true if the identity list is updated by reloading the
+    // keychain. This means that a first party Google app had added or removed
+    // identities.
+    virtual void OnIdentityListChanged(bool keychainReload);
+
     // Handles access token refresh failed events.
     // |identity| is the the identity for which the access token refresh failed.
     // |user_info| is the user info dictionary in the original notification. It
@@ -263,8 +270,15 @@
 
  protected:
   // Fires |OnIdentityListChanged| on all observers.
+  // Deprecated, see FireIdentityListChanged(bool).
   void FireIdentityListChanged();
 
+  // Fires |OnIdentityListChanged| on all observers.
+  // |keychainReload| is true if the identity list is updated by reloading the
+  // keychain. This means that a first party Google app had added or removed
+  // identities.
+  void FireIdentityListChanged(bool keychainReload);
+
   // Fires |OnAccessTokenRefreshFailed| on all observers, with the corresponding
   // identity and user info.
   void FireAccessTokenRefreshFailed(ChromeIdentity* identity,
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
index 9d11980..42696fd 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
@@ -15,6 +15,13 @@
 
 namespace ios {
 
+void ChromeIdentityService::Observer::OnIdentityListChanged(
+    bool keychainReload) {
+  // Call to OnIdentityListChanged() is temporary, until all classes in
+  // ios_internal have migrated to this method.
+  OnIdentityListChanged();
+}
+
 ChromeIdentityService::ChromeIdentityService() {}
 
 ChromeIdentityService::~ChromeIdentityService() {
@@ -157,8 +164,12 @@
 }
 
 void ChromeIdentityService::FireIdentityListChanged() {
+  FireIdentityListChanged(true);
+}
+
+void ChromeIdentityService::FireIdentityListChanged(bool keychainReload) {
   for (auto& observer : observer_list_)
-    observer.OnIdentityListChanged();
+    observer.OnIdentityListChanged(keychainReload);
 }
 
 void ChromeIdentityService::FireAccessTokenRefreshFailed(
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
index ced7a12..ab79eb8a 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
@@ -208,7 +208,7 @@
     ChromeIdentity* identity,
     ForgetIdentityCallback callback) {
   [identities_ removeObject:identity];
-  FireIdentityListChanged();
+  FireIdentityListChanged(false);
   if (callback) {
     // Forgetting an identity is normally an asynchronous operation (that
     // require some network calls), this is replicated here by dispatching
@@ -326,7 +326,7 @@
   if (![identities_ containsObject:identity]) {
     [identities_ addObject:identity];
   }
-  FireIdentityListChanged();
+  FireIdentityListChanged(false);
 }
 
 void FakeChromeIdentityService::SetFakeMDMError(bool fakeMDMError) {
diff --git a/ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm b/ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm
index 0a222b2..b403ae0 100644
--- a/ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm
+++ b/ios/web_view/internal/sync/web_view_profile_invalidation_provider_factory.mm
@@ -61,7 +61,7 @@
 }
 
 WebViewProfileInvalidationProviderFactory::
-    ~WebViewProfileInvalidationProviderFactory() {}
+    ~WebViewProfileInvalidationProviderFactory() = default;
 
 std::unique_ptr<KeyedService>
 WebViewProfileInvalidationProviderFactory::BuildServiceInstanceFor(
@@ -76,15 +76,16 @@
   auto service = std::make_unique<invalidation::FCMInvalidationService>(
       identity_provider.get(),
       base::BindRepeating(
-          &syncer::FCMNetworkHandler::Create,
+          &invalidation::FCMNetworkHandler::Create,
           WebViewGCMProfileServiceFactory::GetForBrowserState(browser_state)
               ->driver(),
           WebViewInstanceIDProfileServiceFactory::GetForBrowserState(
               browser_state)
               ->driver()),
-      base::BindRepeating(&syncer::PerUserTopicSubscriptionManager::Create,
-                          identity_provider.get(), browser_state->GetPrefs(),
-                          browser_state->GetURLLoaderFactory()),
+      base::BindRepeating(
+          &invalidation::PerUserTopicSubscriptionManager::Create,
+          identity_provider.get(), browser_state->GetPrefs(),
+          browser_state->GetURLLoaderFactory()),
       WebViewInstanceIDProfileServiceFactory::GetForBrowserState(browser_state)
           ->driver(),
       browser_state->GetPrefs());
@@ -97,8 +98,8 @@
 void WebViewProfileInvalidationProviderFactory::RegisterBrowserStatePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   ProfileInvalidationProvider::RegisterProfilePrefs(registry);
-  syncer::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry);
-  syncer::PerUserTopicSubscriptionManager::RegisterProfilePrefs(registry);
+  invalidation::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry);
+  invalidation::PerUserTopicSubscriptionManager::RegisterProfilePrefs(registry);
 }
 
 }  // namespace ios_web_view
diff --git a/media/remoting/BUILD.gn b/media/remoting/BUILD.gn
index b01ab5f..bbf4db8 100644
--- a/media/remoting/BUILD.gn
+++ b/media/remoting/BUILD.gn
@@ -125,6 +125,7 @@
       "fake_media_resource.cc",
       "fake_media_resource.h",
       "integration_test.cc",
+      "metrics_unittest.cc",
       "proto_utils_unittest.cc",
       "rpc_broker_unittest.cc",
     ]
diff --git a/media/remoting/metrics.cc b/media/remoting/metrics.cc
index 2cec635..fd3252c 100644
--- a/media/remoting/metrics.cc
+++ b/media/remoting/metrics.cc
@@ -46,8 +46,7 @@
       last_channel_layout_(CHANNEL_LAYOUT_NONE),
       last_sample_rate_(0),
       last_video_codec_(kUnknownVideoCodec),
-      last_video_profile_(VIDEO_CODEC_PROFILE_UNKNOWN),
-      remote_playback_is_disabled_(false) {}
+      last_video_profile_(VIDEO_CODEC_PROFILE_UNKNOWN) {}
 
 SessionMetricsRecorder::~SessionMetricsRecorder() = default;
 
@@ -171,6 +170,21 @@
   remote_playback_is_disabled_ = disabled;
 }
 
+void SessionMetricsRecorder::RecordVideoPixelRateSupport(
+    PixelRateSupport support) {
+  if (did_record_pixel_rate_support_) {
+    return;
+  }
+  did_record_pixel_rate_support_ = true;
+  base::UmaHistogramEnumeration("Media.Remoting.VideoPixelRateSupport",
+                                support);
+}
+
+void SessionMetricsRecorder::RecordCompatibility(
+    RemotingCompatibility compatibility) {
+  base::UmaHistogramEnumeration("Media.Remoting.Compatibility", compatibility);
+}
+
 void SessionMetricsRecorder::RecordAudioConfiguration() {
   UMA_HISTOGRAM_ENUMERATION("Media.Remoting.AudioCodec", last_audio_codec_,
                             kAudioCodecMax + 1);
@@ -219,7 +233,7 @@
 }
 
 RendererMetricsRecorder::RendererMetricsRecorder()
-    : start_time_(base::TimeTicks::Now()), did_record_first_playout_(false) {}
+    : start_time_(base::TimeTicks::Now()) {}
 
 RendererMetricsRecorder::~RendererMetricsRecorder() = default;
 
diff --git a/media/remoting/metrics.h b/media/remoting/metrics.h
index db7f3a6d..017ad9de 100644
--- a/media/remoting/metrics.h
+++ b/media/remoting/metrics.h
@@ -15,6 +15,39 @@
 namespace media {
 namespace remoting {
 
+// The compatibility of a media content with remoting, and the reasons for
+// incompatibilities.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class RemotingCompatibility {
+  kCompatible = 0,
+  kNoAudioNorVideo = 1,
+  kEncryptedVideo = 2,
+  kIncompatibleVideoCodec = 3,
+  kEncryptedAudio = 4,
+  kIncompatibleAudioCodec = 5,
+  kDisabledByPage = 6,
+  kDurationBelowThreshold = 7,
+  // Add new values here. Don't re-number existing values.
+
+  kMaxValue = kDurationBelowThreshold,
+};
+
+// The rate of pixels in a video and whether the receiver supports its playback.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class PixelRateSupport {
+  // Pixels per second is at most the equivalent of 1080p 30fps.
+  k2kSupported = 0,
+  // More than 1080p 30fps and at most 2160p 30fps.
+  k4kSupported = 1,
+  k4kNotSupported = 2,
+  kOver4kNotSupported = 3,
+  // Add new values here. Don't re-number existing values.
+
+  kMaxValue = kOver4kNotSupported,
+};
+
 class SessionMetricsRecorder {
  public:
   SessionMetricsRecorder();
@@ -32,6 +65,14 @@
   void OnPipelineMetadataChanged(const PipelineMetadata& metadata);
   void OnRemotePlaybackDisabled(bool disabled);
 
+  // Records the rate of pixels in a video (bucketed into FHD, 4K, etc.) and
+  // whether the receiver supports its playback. Records only on the first call
+  // for the recorder instance.
+  void RecordVideoPixelRateSupport(PixelRateSupport support);
+
+  // Records the compatibility of a media content with remoting.
+  void RecordCompatibility(RemotingCompatibility compatibility);
+
  private:
   // Whether audio only, video only, or both were played during the session.
   //
@@ -70,7 +111,9 @@
 
   // Last known disabled playback state. This can change before/after a remoting
   // session as well as during one.
-  bool remote_playback_is_disabled_;
+  bool remote_playback_is_disabled_ = false;
+
+  bool did_record_pixel_rate_support_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(SessionMetricsRecorder);
 };
@@ -94,7 +137,7 @@
 
  private:
   const base::TimeTicks start_time_;
-  bool did_record_first_playout_;
+  bool did_record_first_playout_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(RendererMetricsRecorder);
 };
diff --git a/media/remoting/metrics_unittest.cc b/media/remoting/metrics_unittest.cc
new file mode 100644
index 0000000..8ac9b0b6
--- /dev/null
+++ b/media/remoting/metrics_unittest.cc
@@ -0,0 +1,64 @@
+// Copyright 2016 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 "media/remoting/metrics.h"
+
+#include <string>
+
+#include "base/test/metrics/histogram_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Bucket;
+using testing::ElementsAre;
+
+namespace media {
+namespace remoting {
+
+namespace {
+
+class MediaRemotingMetricsTest : public testing::Test {
+ protected:
+  media::remoting::SessionMetricsRecorder recorder_;
+};
+
+}  // namespace
+
+TEST_F(MediaRemotingMetricsTest, RecordVideoPixelRateSupport) {
+  constexpr char kPixelRateSupportHistogramName[] =
+      "Media.Remoting.VideoPixelRateSupport";
+  base::HistogramTester tester;
+  tester.ExpectTotalCount(kPixelRateSupportHistogramName, 0);
+
+  recorder_.RecordVideoPixelRateSupport(PixelRateSupport::k4kNotSupported);
+  recorder_.RecordVideoPixelRateSupport(PixelRateSupport::k2kSupported);
+  recorder_.RecordVideoPixelRateSupport(PixelRateSupport::k4kNotSupported);
+
+  // We record only for the first RecordVideoPixelRateSupport() call for the
+  // given SessionMetricsRecorder instance.
+  EXPECT_THAT(tester.GetAllSamples(kPixelRateSupportHistogramName),
+              ElementsAre(Bucket(
+                  static_cast<int>(PixelRateSupport::k4kNotSupported), 1)));
+}
+
+TEST_F(MediaRemotingMetricsTest, RecordCompatibility) {
+  constexpr char kCompatibilityHistogramName[] = "Media.Remoting.Compatibility";
+  base::HistogramTester tester;
+  tester.ExpectTotalCount(kCompatibilityHistogramName, 0);
+
+  recorder_.RecordCompatibility(RemotingCompatibility::kIncompatibleVideoCodec);
+  recorder_.RecordCompatibility(RemotingCompatibility::kCompatible);
+  recorder_.RecordCompatibility(RemotingCompatibility::kIncompatibleVideoCodec);
+
+  EXPECT_THAT(
+      tester.GetAllSamples(kCompatibilityHistogramName),
+      ElementsAre(
+          Bucket(static_cast<int>(RemotingCompatibility::kCompatible), 1),
+          Bucket(
+              static_cast<int>(RemotingCompatibility::kIncompatibleVideoCodec),
+              2)));
+}
+
+}  // namespace remoting
+}  // namespace media
diff --git a/media/remoting/renderer_controller.cc b/media/remoting/renderer_controller.cc
index ccbddb1b..edc3c7e 100644
--- a/media/remoting/renderer_controller.cc
+++ b/media/remoting/renderer_controller.cc
@@ -9,6 +9,7 @@
 #include "base/time/default_tick_clock.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
+#include "media/remoting/metrics.h"
 
 #if defined(OS_ANDROID)
 #include "media/base/android/media_codec_util.h"
@@ -17,14 +18,17 @@
 namespace media {
 namespace remoting {
 
+using mojom::RemotingSinkAudioCapability;
+using mojom::RemotingSinkVideoCapability;
+
 namespace {
 
 // The duration to delay the start of media remoting to ensure all preconditions
 // are held stable before switching to media remoting.
 constexpr base::TimeDelta kDelayedStart = base::TimeDelta::FromSeconds(5);
 
-constexpr int kPixelPerSec4K = 3840 * 2160 * 30;  // 4k 30fps.
-constexpr int kPixelPerSec2K = 1920 * 1080 * 30;  // 1080p 30fps.
+constexpr int kPixelsPerSec4k = 3840 * 2160 * 30;  // 4k 30fps.
+constexpr int kPixelsPerSec2k = 1920 * 1080 * 30;  // 1080p 30fps.
 
 // The minimum media element duration that is allowed for media remoting.
 // Frequent switching into and out of media remoting for short-duration media
@@ -327,62 +331,12 @@
 
 bool RendererController::IsVideoCodecSupported() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(has_video());
-
-  // Media Remoting doesn't support encrypted media.
-  if (pipeline_metadata_.video_decoder_config.is_encrypted())
-    return false;
-
-  switch (pipeline_metadata_.video_decoder_config.codec()) {
-    case VideoCodec::kCodecH264:
-      return HasVideoCapability(mojom::RemotingSinkVideoCapability::CODEC_H264);
-    case VideoCodec::kCodecVP8:
-      return HasVideoCapability(mojom::RemotingSinkVideoCapability::CODEC_VP8);
-    case VideoCodec::kCodecVP9:
-      return HasVideoCapability(mojom::RemotingSinkVideoCapability::CODEC_VP9);
-    case VideoCodec::kCodecHEVC:
-      return HasVideoCapability(mojom::RemotingSinkVideoCapability::CODEC_HEVC);
-    default:
-      VLOG(2) << "Remoting does not support video codec: "
-              << pipeline_metadata_.video_decoder_config.codec();
-      return false;
-  }
+  return GetVideoCompatibility() == RemotingCompatibility::kCompatible;
 }
 
 bool RendererController::IsAudioCodecSupported() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(has_audio());
-
-  // Media Remoting doesn't support encrypted media.
-  if (pipeline_metadata_.audio_decoder_config.is_encrypted())
-    return false;
-
-  switch (pipeline_metadata_.audio_decoder_config.codec()) {
-    case AudioCodec::kCodecAAC:
-      return HasAudioCapability(mojom::RemotingSinkAudioCapability::CODEC_AAC);
-    case AudioCodec::kCodecOpus:
-      return HasAudioCapability(mojom::RemotingSinkAudioCapability::CODEC_OPUS);
-    case AudioCodec::kCodecMP3:
-    case AudioCodec::kCodecPCM:
-    case AudioCodec::kCodecVorbis:
-    case AudioCodec::kCodecFLAC:
-    case AudioCodec::kCodecAMR_NB:
-    case AudioCodec::kCodecAMR_WB:
-    case AudioCodec::kCodecPCM_MULAW:
-    case AudioCodec::kCodecGSM_MS:
-    case AudioCodec::kCodecPCM_S16BE:
-    case AudioCodec::kCodecPCM_S24BE:
-    case AudioCodec::kCodecEAC3:
-    case AudioCodec::kCodecPCM_ALAW:
-    case AudioCodec::kCodecALAC:
-    case AudioCodec::kCodecAC3:
-      return HasAudioCapability(
-          mojom::RemotingSinkAudioCapability::CODEC_BASELINE_SET);
-    default:
-      VLOG(2) << "Remoting does not support audio codec: "
-              << pipeline_metadata_.audio_decoder_config.codec();
-      return false;
-  }
+  return GetAudioCompatibility() == RemotingCompatibility::kCompatible;
 }
 
 void RendererController::OnPlaying() {
@@ -400,25 +354,103 @@
   CancelDelayedStart();
 }
 
-bool RendererController::CanBeRemoting() const {
+RemotingCompatibility RendererController::GetVideoCompatibility() const {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(has_video());
 
-  if (!client_)
-    return false;  // No way to switch to the remoting renderer.
+  // Media Remoting doesn't support encrypted media.
+  if (pipeline_metadata_.video_decoder_config.is_encrypted())
+    return RemotingCompatibility::kEncryptedVideo;
 
-  if (permanently_disable_remoting_)
-    return false;
+  bool compatible = false;
+  switch (pipeline_metadata_.video_decoder_config.codec()) {
+    case VideoCodec::kCodecH264:
+      compatible = HasVideoCapability(RemotingSinkVideoCapability::CODEC_H264);
+      break;
+    case VideoCodec::kCodecVP8:
+      compatible = HasVideoCapability(RemotingSinkVideoCapability::CODEC_VP8);
+      break;
+    case VideoCodec::kCodecVP9:
+      compatible = HasVideoCapability(RemotingSinkVideoCapability::CODEC_VP9);
+      break;
+    case VideoCodec::kCodecHEVC:
+      compatible = HasVideoCapability(RemotingSinkVideoCapability::CODEC_HEVC);
+      break;
+    default:
+      VLOG(2) << "Remoting does not support video codec: "
+              << pipeline_metadata_.video_decoder_config.codec();
+  }
+  return compatible ? RemotingCompatibility::kCompatible
+                    : RemotingCompatibility::kIncompatibleVideoCodec;
+}
 
-  if (!IsAudioOrVideoSupported())
-    return false;
+RemotingCompatibility RendererController::GetAudioCompatibility() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(has_audio());
+
+  // Media Remoting doesn't support encrypted media.
+  if (pipeline_metadata_.audio_decoder_config.is_encrypted())
+    return RemotingCompatibility::kEncryptedAudio;
+
+  bool compatible = false;
+  switch (pipeline_metadata_.audio_decoder_config.codec()) {
+    case AudioCodec::kCodecAAC:
+      compatible = HasAudioCapability(RemotingSinkAudioCapability::CODEC_AAC);
+      break;
+    case AudioCodec::kCodecOpus:
+      compatible = HasAudioCapability(RemotingSinkAudioCapability::CODEC_OPUS);
+      break;
+    case AudioCodec::kCodecMP3:
+    case AudioCodec::kCodecPCM:
+    case AudioCodec::kCodecVorbis:
+    case AudioCodec::kCodecFLAC:
+    case AudioCodec::kCodecAMR_NB:
+    case AudioCodec::kCodecAMR_WB:
+    case AudioCodec::kCodecPCM_MULAW:
+    case AudioCodec::kCodecGSM_MS:
+    case AudioCodec::kCodecPCM_S16BE:
+    case AudioCodec::kCodecPCM_S24BE:
+    case AudioCodec::kCodecEAC3:
+    case AudioCodec::kCodecPCM_ALAW:
+    case AudioCodec::kCodecALAC:
+    case AudioCodec::kCodecAC3:
+      compatible =
+          HasAudioCapability(RemotingSinkAudioCapability::CODEC_BASELINE_SET);
+      break;
+    default:
+      VLOG(2) << "Remoting does not support audio codec: "
+              << pipeline_metadata_.audio_decoder_config.codec();
+  }
+  return compatible ? RemotingCompatibility::kCompatible
+                    : RemotingCompatibility::kIncompatibleAudioCodec;
+}
+
+RemotingCompatibility RendererController::GetCompatibility() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(client_);
 
   if (is_remote_playback_disabled_)
-    return false;
+    return RemotingCompatibility::kDisabledByPage;
+
+  if (!has_video() && !has_audio())
+    return RemotingCompatibility::kNoAudioNorVideo;
+
+  if (has_video()) {
+    RemotingCompatibility compatibility = GetVideoCompatibility();
+    if (compatibility != RemotingCompatibility::kCompatible)
+      return compatibility;
+  }
+
+  if (has_audio()) {
+    RemotingCompatibility compatibility = GetAudioCompatibility();
+    if (compatibility != RemotingCompatibility::kCompatible)
+      return compatibility;
+  }
 
   if (client_->Duration() <= kMinRemotingMediaDurationInSec)
-    return false;
+    return RemotingCompatibility::kDurationBelowThreshold;
 
-  return true;
+  return RemotingCompatibility::kCompatible;
 }
 
 bool RendererController::IsAudioOrVideoSupported() const {
@@ -431,26 +463,25 @@
                                               StopTrigger stop_trigger) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  bool should_be_remoting = CanBeRemoting();
-
   // Being the dominant visible content is the signal that starts remote
   // rendering.
-  should_be_remoting &=
-      (is_dominant_content_ && !encountered_renderer_fatal_error_);
+  // Also, only switch to remoting when media is playing. Since the renderer is
+  // created when video starts loading, the receiver would display a black
+  // screen if switching to remoting while paused. Thus, the user experience is
+  // improved by not starting remoting until playback resumes.
+  bool should_be_remoting = client_ && !encountered_renderer_fatal_error_ &&
+                            is_dominant_content_ && !is_paused_;
+  if (should_be_remoting) {
+    const RemotingCompatibility compatibility = GetCompatibility();
+    metrics_recorder_.RecordCompatibility(compatibility);
+    should_be_remoting = compatibility == RemotingCompatibility::kCompatible;
+  }
 
   if ((remote_rendering_started_ ||
        delayed_start_stability_timer_.IsRunning()) == should_be_remoting) {
     return;
   }
 
-  // Only switch to remoting when media is playing. Since the renderer is
-  // created when video starts loading/playing, receiver will display a black
-  // screen before video starts playing if switching to remoting when paused.
-  // Thus, the user experience is improved by not starting remoting until
-  // playback resumes.
-  if (should_be_remoting && is_paused_)
-    return;
-
   if (should_be_remoting) {
     WaitForStabilityBeforeStart(start_trigger);
   } else if (delayed_start_stability_timer_.IsRunning()) {
@@ -498,13 +529,10 @@
     const double frame_rate =
         (client_->DecodedFrameCount() - decoded_frame_count_before_delay) /
         elapsed.InSecondsF();
-    const double pixel_per_sec =
+    const double pixels_per_second =
         frame_rate * pipeline_metadata_.natural_size.GetArea();
-    if ((pixel_per_sec > kPixelPerSec4K) ||
-        ((pixel_per_sec > kPixelPerSec2K) &&
-         !HasVideoCapability(mojom::RemotingSinkVideoCapability::SUPPORT_4K))) {
-      VLOG(1) << "Media remoting is not supported: frame_rate = " << frame_rate
-              << " resolution = " << pipeline_metadata_.natural_size.ToString();
+    const bool supported = RecordPixelRateSupport(pixels_per_second);
+    if (!supported) {
       permanently_disable_remoting_ = true;
       return;
     }
@@ -518,6 +546,28 @@
   remoter_->Start();
 }
 
+bool RendererController::RecordPixelRateSupport(double pixels_per_second) {
+  if (pixels_per_second <= kPixelsPerSec2k) {
+    metrics_recorder_.RecordVideoPixelRateSupport(
+        PixelRateSupport::k2kSupported);
+    return true;
+  }
+  if (pixels_per_second <= kPixelsPerSec4k) {
+    if (HasVideoCapability(mojom::RemotingSinkVideoCapability::SUPPORT_4K)) {
+      metrics_recorder_.RecordVideoPixelRateSupport(
+          PixelRateSupport::k4kSupported);
+      return true;
+    } else {
+      metrics_recorder_.RecordVideoPixelRateSupport(
+          PixelRateSupport::k4kNotSupported);
+      return false;
+    }
+  }
+  metrics_recorder_.RecordVideoPixelRateSupport(
+      PixelRateSupport::kOver4kNotSupported);
+  return false;
+}
+
 void RendererController::OnRendererFatalError(StopTrigger stop_trigger) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
diff --git a/media/remoting/renderer_controller.h b/media/remoting/renderer_controller.h
index 8c22bbf0..02e7f00 100644
--- a/media/remoting/renderer_controller.h
+++ b/media/remoting/renderer_controller.h
@@ -117,11 +117,14 @@
   bool IsAudioCodecSupported() const;
   bool IsAudioOrVideoSupported() const;
 
-  // Returns true if all of the technical requirements for the media pipeline
-  // and remote rendering are being met. This does not include environmental
-  // conditions, such as the content being dominant in the viewport, available
-  // network bandwidth, etc.
-  bool CanBeRemoting() const;
+  // Returns |kCompatible| if all of the technical requirements for the media
+  // pipeline and remote rendering are being met, and the first detected
+  // reason if incompatible. This does not include environmental conditions,
+  // such as the content being dominant in the viewport, available network
+  // bandwidth, etc.
+  RemotingCompatibility GetVideoCompatibility() const;
+  RemotingCompatibility GetAudioCompatibility() const;
+  RemotingCompatibility GetCompatibility() const;
 
   // Determines whether to enter or leave Remoting mode and switches if
   // necessary. Each call to this method could cause a remoting session to be
@@ -146,6 +149,10 @@
                                 unsigned decoded_frame_count_before_delay,
                                 base::TimeTicks delayed_start_time);
 
+  // Records in a histogram and returns whether the receiver supports the given
+  // pixel rate.
+  bool RecordPixelRateSupport(double pixels_per_second);
+
   // Queries on remoting sink capabilities.
   bool HasVideoCapability(mojom::RemotingSinkVideoCapability capability) const;
   bool HasAudioCapability(mojom::RemotingSinkAudioCapability capability) const;
diff --git a/media/webrtc/webrtc_switches.cc b/media/webrtc/webrtc_switches.cc
index febee19..3c16994 100644
--- a/media/webrtc/webrtc_switches.cc
+++ b/media/webrtc/webrtc_switches.cc
@@ -20,11 +20,10 @@
 
 namespace features {
 
-// Enables multi channel capture audio to be processed without
-// downmixing in the WebRTC audio processing module when running in the renderer
-// process.
+// Enables multichannel capture audio to be processed without downmixing in the
+// WebRTC audio processing module.
 const base::Feature kWebRtcEnableCaptureMultiChannelApm{
-    "WebRtcEnableCaptureMultiChannelApm", base::FEATURE_DISABLED_BY_DEFAULT};
+    "WebRtcEnableCaptureMultiChannelApm", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Kill-switch allowing deactivation of the support for 48 kHz internal
 // processing in the WebRTC audio processing module when running on an ARM
diff --git a/net/dns/dns_config_service.cc b/net/dns/dns_config_service.cc
index d475626..12f155e 100644
--- a/net/dns/dns_config_service.cc
+++ b/net/dns/dns_config_service.cc
@@ -6,8 +6,14 @@
 
 #include <string>
 
+#include "base/bind.h"
 #include "base/check_op.h"
+#include "base/location.h"
+#include "base/logging.h"
 #include "base/notreached.h"
+#include "base/optional.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
 
 namespace net {
 
@@ -15,12 +21,14 @@
 const base::TimeDelta DnsConfigService::kInvalidationTimeout =
     base::TimeDelta::FromMilliseconds(150);
 
-DnsConfigService::DnsConfigService()
+DnsConfigService::DnsConfigService(
+    base::Optional<base::TimeDelta> config_change_delay)
     : watch_failed_(false),
       have_config_(false),
       have_hosts_(false),
       need_update_(false),
-      last_sent_empty_(true) {
+      last_sent_empty_(true),
+      config_change_delay_(config_change_delay) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
@@ -33,7 +41,8 @@
   DCHECK(!callback.is_null());
   DCHECK(callback_.is_null());
   callback_ = callback;
-  ReadNow();
+  ReadConfigNow();
+  ReadHostsNow();
 }
 
 void DnsConfigService::WatchConfig(const CallbackType& callback) {
@@ -42,7 +51,8 @@
   DCHECK(callback_.is_null());
   callback_ = callback;
   watch_failed_ = !StartWatching();
-  ReadNow();
+  ReadConfigNow();
+  ReadHostsNow();
 }
 
 void DnsConfigService::RefreshConfig() {
@@ -50,6 +60,27 @@
   NOTREACHED();
 }
 
+DnsConfigService::Watcher::Watcher(DnsConfigService* service)
+    : service_(service) {}
+
+DnsConfigService::Watcher::~Watcher() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void DnsConfigService::Watcher::OnConfigChanged(bool succeeded) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  service_->OnConfigChanged(succeeded);
+}
+
+void DnsConfigService::Watcher::OnHostsChanged(bool succeeded) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  service_->OnHostsChanged(succeeded);
+}
+
+void DnsConfigService::Watcher::CheckOnCorrectSequence() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
 void DnsConfigService::InvalidateConfig() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!have_config_)
@@ -135,4 +166,37 @@
   }
 }
 
+void DnsConfigService::OnConfigChanged(bool succeeded) {
+  if (config_change_delay_) {
+    // Ignore transient flutter of config source by delaying the signal a bit.
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&DnsConfigService::OnConfigChangedDelayed,
+                       weak_factory_.GetWeakPtr(), succeeded),
+        config_change_delay_.value());
+  } else {
+    OnConfigChangedDelayed(succeeded);
+  }
+}
+
+void DnsConfigService::OnHostsChanged(bool succeeded) {
+  InvalidateHosts();
+  if (succeeded) {
+    ReadHostsNow();
+  } else {
+    LOG(ERROR) << "DNS hosts watch failed.";
+    watch_failed_ = true;
+  }
+}
+
+void DnsConfigService::OnConfigChangedDelayed(bool succeeded) {
+  InvalidateConfig();
+  if (succeeded) {
+    ReadConfigNow();
+  } else {
+    LOG(ERROR) << "DNS config watch failed.";
+    watch_failed_ = true;
+  }
+}
+
 }  // namespace net
diff --git a/net/dns/dns_config_service.h b/net/dns/dns_config_service.h
index c0af67e4..e9a1bc3 100644
--- a/net/dns/dns_config_service.h
+++ b/net/dns/dns_config_service.h
@@ -9,6 +9,8 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -38,7 +40,13 @@
   // reading system DNS settings is not supported on the current platform.
   static std::unique_ptr<DnsConfigService> CreateSystemService();
 
-  DnsConfigService();
+  // On detecting config change, will post and wait `config_change_delay` before
+  // triggering refreshes. Will trigger refreshes synchronously on nullopt.
+  // Useful for platforms where multiple changes may be made and detected before
+  // the config is stabilized and ready to be read.
+  explicit DnsConfigService(
+      base::Optional<base::TimeDelta> config_change_delay =
+          base::TimeDelta::FromMilliseconds(50));
   virtual ~DnsConfigService();
 
   // Attempts to read the configuration. Will run |callback| when succeeded.
@@ -56,9 +64,47 @@
   // network-stack-external notifications of DNS config changes.
   virtual void RefreshConfig();
 
+  void set_watch_failed_for_testing(bool watch_failed) {
+    watch_failed_ = watch_failed;
+  }
+
  protected:
+  // Watcher to observe for changes to DNS config or HOSTS (via overriding
+  // `Watch()` with platform specifics) and trigger necessary refreshes on
+  // changes.
+  class Watcher {
+   public:
+    // `service` is expected to own the created Watcher and thus stay valid for
+    // the lifetime of the created Watcher.
+    explicit Watcher(DnsConfigService* service);
+    virtual ~Watcher();
+
+    Watcher(const Watcher&) = delete;
+    Watcher& operator=(const Watcher&) = delete;
+
+    virtual bool Watch() = 0;
+
+   protected:
+    // Hooks for detected changes. `succeeded` false to indicate that there was
+    // an error watching for the change.
+    void OnConfigChanged(bool succeeded);
+    void OnHostsChanged(bool succeeded);
+
+    void CheckOnCorrectSequence();
+
+   private:
+    void OnConfigChangedDelayed(bool success);
+
+    // Back pointer. `this` is expected to be owned by `service_`, making this
+    // raw pointer safe.
+    DnsConfigService* const service_;
+
+    SEQUENCE_CHECKER(sequence_checker_);
+  };
+
   // Immediately attempts to read the current configuration.
-  virtual void ReadNow() = 0;
+  virtual void ReadConfigNow() = 0;
+  virtual void ReadHostsNow() = 0;
   // Registers system watchers. Returns true iff succeeds.
   virtual bool StartWatching() = 0;
 
@@ -72,8 +118,6 @@
   // Called with new hosts. Rest of the config is assumed unchanged.
   void OnHostsRead(const DnsHosts& hosts);
 
-  void set_watch_failed(bool value) { watch_failed_ = value; }
-
   SEQUENCE_CHECKER(sequence_checker_);
 
  private:
@@ -83,6 +127,12 @@
   // Called when the config becomes complete. Stops the timer.
   void OnCompleteConfig();
 
+  // Hooks for Watcher change notifications. `succeeded` false to indicate that
+  // there was an error watching for the change.
+  void OnConfigChanged(bool succeeded);
+  void OnHostsChanged(bool succeeded);
+  void OnConfigChangedDelayed(bool succeeded);
+
   CallbackType callback_;
 
   DnsConfig dns_config_;
@@ -99,9 +149,13 @@
   // Set when |timer_| expires.
   bool last_sent_empty_;
 
+  const base::Optional<base::TimeDelta> config_change_delay_;
+
   // Started in Invalidate*, cleared in On*Read.
   base::OneShotTimer timer_;
 
+  base::WeakPtrFactory<DnsConfigService> weak_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(DnsConfigService);
 };
 
diff --git a/net/dns/dns_config_service_fuchsia.cc b/net/dns/dns_config_service_fuchsia.cc
index 1673b6d..8d3062a 100644
--- a/net/dns/dns_config_service_fuchsia.cc
+++ b/net/dns/dns_config_service_fuchsia.cc
@@ -15,7 +15,11 @@
 DnsConfigServiceFuchsia::DnsConfigServiceFuchsia() = default;
 DnsConfigServiceFuchsia::~DnsConfigServiceFuchsia() = default;
 
-void DnsConfigServiceFuchsia::ReadNow() {
+void DnsConfigServiceFuchsia::ReadConfigNow() {
+  // TODO(crbug.com/950717): Implement this method.
+}
+
+void DnsConfigServiceFuchsia::ReadHostsNow() {
   // TODO(crbug.com/950717): Implement this method.
 }
 
diff --git a/net/dns/dns_config_service_fuchsia.h b/net/dns/dns_config_service_fuchsia.h
index 79488e66..69b5ed3 100644
--- a/net/dns/dns_config_service_fuchsia.h
+++ b/net/dns/dns_config_service_fuchsia.h
@@ -21,7 +21,8 @@
 
  protected:
   // DnsConfigService overrides.
-  void ReadNow() override;
+  void ReadConfigNow() override;
+  void ReadHostsNow() override;
   bool StartWatching() override;
 
  private:
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index 19c038fe..c5a25c66 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -15,9 +15,9 @@
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/scoped_blocking_call.h"
-#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "net/base/ip_address.h"
@@ -224,12 +224,15 @@
 
 }  // namespace
 
-class DnsConfigServicePosix::Watcher {
+class DnsConfigServicePosix::Watcher : public DnsConfigService::Watcher {
  public:
-  explicit Watcher(DnsConfigServicePosix* service) : service_(service) {}
-  ~Watcher() = default;
+  explicit Watcher(DnsConfigServicePosix* service)
+      : DnsConfigService::Watcher(service) {}
+  ~Watcher() override = default;
 
-  bool Watch() {
+  bool Watch() override {
+    CheckOnCorrectSequence();
+
     bool success = true;
     if (!config_watcher_.Watch(base::BindRepeating(&Watcher::OnConfigChanged,
                                                    base::Unretained(this)))) {
@@ -239,10 +242,11 @@
 // Hosts file should never change on Android or iOS (and watching it on Android
 // is problematic; see http://crbug.com/600442), so don't watch it there.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
-    if (!hosts_watcher_.Watch(base::FilePath(service_->file_path_hosts_),
-                              base::FilePathWatcher::Type::kNonRecursive,
-                              base::BindRepeating(&Watcher::OnHostsChanged,
-                                                  base::Unretained(this)))) {
+    if (!hosts_watcher_.Watch(
+            base::FilePath(kFilePathHosts),
+            base::FilePathWatcher::Type::kNonRecursive,
+            base::BindRepeating(&Watcher::OnHostsFilePathWatcherChange,
+                                base::Unretained(this)))) {
       LOG(ERROR) << "DNS hosts watch failed to start.";
       success = false;
     }
@@ -251,32 +255,17 @@
   }
 
  private:
-  void OnConfigChanged(bool succeeded) {
-    // Ignore transient flutter of resolv.conf by delaying the signal a bit.
-    const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(50);
-    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&Watcher::OnConfigChangedDelayed,
-                       weak_factory_.GetWeakPtr(), succeeded),
-        kDelay);
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  void OnHostsFilePathWatcherChange(const base::FilePath& path, bool error) {
+    OnHostsChanged(!error);
   }
+#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
 
-  void OnConfigChangedDelayed(bool succeeded) {
-    service_->OnConfigChanged(succeeded);
-  }
-
-  void OnHostsChanged(const base::FilePath& path, bool error) {
-    service_->OnHostsChanged(!error);
-  }
-
-  DnsConfigServicePosix* const service_;
   DnsConfigWatcher config_watcher_;
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
   base::FilePathWatcher hosts_watcher_;
 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
 
-  base::WeakPtrFactory<Watcher> weak_factory_{this};
-
   DISALLOW_COPY_AND_ASSIGN(Watcher);
 };
 
@@ -321,9 +310,7 @@
 class DnsConfigServicePosix::HostsReader : public SerialWorker {
  public:
   explicit HostsReader(DnsConfigServicePosix* service)
-      : service_(service),
-        file_path_hosts_(service->file_path_hosts_),
-        success_(false) {
+      : service_(service), success_(false) {
     // Allow execution on another thread; nothing thread-specific about
     // constructor.
     DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -335,7 +322,7 @@
   void DoWork() override {
     base::ScopedBlockingCall scoped_blocking_call(
         FROM_HERE, base::BlockingType::MAY_BLOCK);
-    success_ = ParseHostsFile(file_path_hosts_, &hosts_);
+    success_ = ParseHostsFile(base::FilePath(kFilePathHosts), &hosts_);
   }
 
   void OnWorkFinished() override {
@@ -350,8 +337,6 @@
   // DoWork(), since service may be destroyed while SerialWorker is running
   // on worker thread.
   DnsConfigServicePosix* const service_;
-  // Hosts file path to parse.
-  const base::FilePath file_path_hosts_;
   // Written in DoWork, read in OnWorkFinished, no locking necessary.
   DnsHosts hosts_;
   bool success_;
@@ -359,8 +344,7 @@
   DISALLOW_COPY_AND_ASSIGN(HostsReader);
 };
 
-DnsConfigServicePosix::DnsConfigServicePosix()
-    : file_path_hosts_(kFilePathHosts) {
+DnsConfigServicePosix::DnsConfigServicePosix() {
   // Allow constructing on one thread and living on another.
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
@@ -373,11 +357,15 @@
 void DnsConfigServicePosix::RefreshConfig() {
   InvalidateConfig();
   InvalidateHosts();
-  ReadNow();
+  ReadConfigNow();
+  ReadHostsNow();
 }
 
-void DnsConfigServicePosix::ReadNow() {
+void DnsConfigServicePosix::ReadConfigNow() {
   config_reader_->WorkNow();
+}
+
+void DnsConfigServicePosix::ReadHostsNow() {
   hosts_reader_->WorkNow();
 }
 
@@ -388,26 +376,6 @@
   return watcher_->Watch();
 }
 
-void DnsConfigServicePosix::OnConfigChanged(bool succeeded) {
-  InvalidateConfig();
-  if (succeeded) {
-    config_reader_->WorkNow();
-  } else {
-    LOG(ERROR) << "DNS config watch failed.";
-    set_watch_failed(true);
-  }
-}
-
-void DnsConfigServicePosix::OnHostsChanged(bool succeeded) {
-  InvalidateHosts();
-  if (succeeded) {
-    hosts_reader_->WorkNow();
-  } else {
-    LOG(ERROR) << "DNS hosts watch failed.";
-    set_watch_failed(true);
-  }
-}
-
 void DnsConfigServicePosix::CreateReaders() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!config_reader_);
diff --git a/net/dns/dns_config_service_posix.h b/net/dns/dns_config_service_posix.h
index 12fa1037..f7fdbf6 100644
--- a/net/dns/dns_config_service_posix.h
+++ b/net/dns/dns_config_service_posix.h
@@ -41,7 +41,8 @@
 
  protected:
   // DnsConfigService:
-  void ReadNow() override;
+  void ReadConfigNow() override;
+  void ReadHostsNow() override;
   bool StartWatching() override;
 
   // Create |config_reader_| and |hosts_reader_|.
@@ -54,12 +55,7 @@
   class ConfigReader;
   class HostsReader;
 
-  void OnConfigChanged(bool succeeded);
-  void OnHostsChanged(bool succeeded);
-
   std::unique_ptr<Watcher> watcher_;
-  // Allow a mock hosts file for testing purposes.
-  const base::FilePath::CharType* file_path_hosts_;
   scoped_refptr<ConfigReader> config_reader_;
   scoped_refptr<HostsReader> hosts_reader_;
 
diff --git a/net/dns/dns_config_service_unittest.cc b/net/dns/dns_config_service_unittest.cc
index d9a7732..5f7e0c2 100644
--- a/net/dns/dns_config_service_unittest.cc
+++ b/net/dns/dns_config_service_unittest.cc
@@ -187,7 +187,7 @@
   EXPECT_TRUE(last_config_.Equals(config1));
 
   // Simulate watch failure.
-  service_->set_watch_failed(true);
+  service_->set_watch_failed_for_testing(true);
   service_->InvalidateConfig();
   WaitForConfig(TestTimeouts::action_timeout());
   EXPECT_FALSE(last_config_.Equals(config1));
diff --git a/net/dns/dns_config_service_win.cc b/net/dns/dns_config_service_win.cc
index 8e385ab..930df26f 100644
--- a/net/dns/dns_config_service_win.cc
+++ b/net/dns/dns_config_service_win.cc
@@ -574,14 +574,18 @@
 // Watches registry and HOSTS file for changes. Must live on a sequence which
 // allows IO.
 class DnsConfigServiceWin::Watcher
-    : public NetworkChangeNotifier::IPAddressObserver {
+    : public NetworkChangeNotifier::IPAddressObserver,
+      public DnsConfigService::Watcher {
  public:
-  explicit Watcher(DnsConfigServiceWin* service) : service_(service) {}
+  explicit Watcher(DnsConfigServiceWin* service)
+      : DnsConfigService::Watcher(service) {}
   ~Watcher() override { NetworkChangeNotifier::RemoveIPAddressObserver(this); }
 
-  bool Watch() {
-    RegistryWatcher::CallbackType callback = base::BindRepeating(
-        &DnsConfigServiceWin::OnConfigChanged, base::Unretained(service_));
+  bool Watch() override {
+    CheckOnCorrectSequence();
+
+    RegistryWatcher::CallbackType callback =
+        base::BindRepeating(&Watcher::OnConfigChanged, base::Unretained(this));
 
     bool success = true;
 
@@ -603,10 +607,10 @@
     dnscache_watcher_.Watch(kDnscachePath, callback);
     policy_watcher_.Watch(kPolicyPath, callback);
 
-    if (!hosts_watcher_.Watch(GetHostsPath(),
-                              base::FilePathWatcher::Type::kNonRecursive,
-                              base::BindRepeating(&Watcher::OnHostsChanged,
-                                                  base::Unretained(this)))) {
+    if (!hosts_watcher_.Watch(
+            GetHostsPath(), base::FilePathWatcher::Type::kNonRecursive,
+            base::BindRepeating(&Watcher::OnHostsFilePathWatcherChange,
+                                base::Unretained(this)))) {
       LOG(ERROR) << "DNS hosts watch failed to start.";
       success = false;
     } else {
@@ -617,20 +621,18 @@
   }
 
  private:
-  void OnHostsChanged(const base::FilePath& path, bool error) {
+  void OnHostsFilePathWatcherChange(const base::FilePath& path, bool error) {
     if (error)
       NetworkChangeNotifier::RemoveIPAddressObserver(this);
-    service_->OnHostsChanged(!error);
+    OnHostsChanged(!error);
   }
 
   // NetworkChangeNotifier::IPAddressObserver:
   void OnIPAddressChanged() override {
     // Need to update non-loopback IP of local host.
-    service_->OnHostsChanged(true);
+    OnHostsChanged(true);
   }
 
-  DnsConfigServiceWin* service_;
-
   RegistryWatcher tcpip_watcher_;
   RegistryWatcher tcpip6_watcher_;
   RegistryWatcher dnscache_watcher_;
@@ -716,7 +718,8 @@
   DISALLOW_COPY_AND_ASSIGN(HostsReader);
 };
 
-DnsConfigServiceWin::DnsConfigServiceWin() {
+DnsConfigServiceWin::DnsConfigServiceWin()
+    : DnsConfigService(base::nullopt /* config_change_delay */) {
   // Allow constructing on one sequence and living on another.
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
@@ -728,8 +731,11 @@
     hosts_reader_->Cancel();
 }
 
-void DnsConfigServiceWin::ReadNow() {
+void DnsConfigServiceWin::ReadConfigNow() {
   config_reader_->WorkNow();
+}
+
+void DnsConfigServiceWin::ReadHostsNow() {
   hosts_reader_->WorkNow();
 }
 
@@ -743,25 +749,6 @@
   return watcher_->Watch();
 }
 
-void DnsConfigServiceWin::OnConfigChanged(bool succeeded) {
-  InvalidateConfig();
-  config_reader_->WorkNow();
-  if (!succeeded) {
-    LOG(ERROR) << "DNS config watch failed.";
-    set_watch_failed(true);
-  }
-}
-
-void DnsConfigServiceWin::OnHostsChanged(bool succeeded) {
-  InvalidateHosts();
-  if (succeeded) {
-    hosts_reader_->WorkNow();
-  } else {
-    LOG(ERROR) << "DNS hosts watch failed.";
-    set_watch_failed(true);
-  }
-}
-
 }  // namespace internal
 
 // static
diff --git a/net/dns/dns_config_service_win.h b/net/dns/dns_config_service_win.h
index de1d1ac5..97dcfb6 100644
--- a/net/dns/dns_config_service_win.h
+++ b/net/dns/dns_config_service_win.h
@@ -137,12 +137,10 @@
   class HostsReader;
 
   // DnsConfigService:
-  void ReadNow() override;
+  void ReadConfigNow() override;
+  void ReadHostsNow() override;
   bool StartWatching() override;
 
-  void OnConfigChanged(bool succeeded);
-  void OnHostsChanged(bool succeeded);
-
   std::unique_ptr<Watcher> watcher_;
   scoped_refptr<ConfigReader> config_reader_;
   scoped_refptr<HostsReader> hosts_reader_;
diff --git a/net/dns/test_dns_config_service.cc b/net/dns/test_dns_config_service.cc
index af928627..3e3a1d55 100644
--- a/net/dns/test_dns_config_service.cc
+++ b/net/dns/test_dns_config_service.cc
@@ -6,7 +6,8 @@
 
 namespace net {
 
-TestDnsConfigService::TestDnsConfigService() = default;
+TestDnsConfigService::TestDnsConfigService()
+    : DnsConfigService(base::nullopt /* config_change_delay */) {}
 
 TestDnsConfigService::~TestDnsConfigService() = default;
 
diff --git a/net/dns/test_dns_config_service.h b/net/dns/test_dns_config_service.h
index 1b63ec7..3b4fb06b 100644
--- a/net/dns/test_dns_config_service.h
+++ b/net/dns/test_dns_config_service.h
@@ -20,7 +20,8 @@
   TestDnsConfigService();
   ~TestDnsConfigService() override;
 
-  void ReadNow() override {}
+  void ReadConfigNow() override {}
+  void ReadHostsNow() override {}
   bool StartWatching() override;
 
   // Expose the protected methods to this test suite.
@@ -36,10 +37,6 @@
     DnsConfigService::OnHostsRead(hosts);
   }
 
-  void set_watch_failed(bool value) {
-    DnsConfigService::set_watch_failed(value);
-  }
-
   void RefreshConfig() override;
 
   void SetConfigForRefresh(DnsConfig config) {
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index d443a21..6acb5e0 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -132,6 +132,7 @@
 constexpr char kJSMetadataType[] = "metadata";
 constexpr char kJSMetadataData[] = "metadataData";
 constexpr char kJSVersion[] = "version";
+constexpr char kJSLinearized[] = "linearized";
 constexpr char kJSTitle[] = "title";
 constexpr char kJSAuthor[] = "author";
 constexpr char kJSSubject[] = "subject";
@@ -2429,6 +2430,9 @@
   if (!version.empty())
     metadata_data.Set(pp::Var(kJSVersion), pp::Var(base::UTF16ToUTF8(version)));
 
+  metadata_data.Set(pp::Var(kJSLinearized),
+                    pp::Var(document_metadata.linearized));
+
   if (!document_metadata.title.empty())
     metadata_data.Set(pp::Var(kJSTitle), pp::Var(document_metadata.title));
 
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index d177c05..f01fa92 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -155,7 +155,11 @@
 // See also https://crbug.com/920634
 const base::Feature kRequestInitiatorSiteLockEnfocement = {
     "RequestInitiatorSiteLockEnfocement",
+#if defined(OS_ANDROID)
+    base::FEATURE_DISABLED_BY_DEFAULT};
+#else
     base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
 
 // When the CertVerifierService is enabled, certificate verification will not be
 // performed in the network service, but will instead be brokered to a separate
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 525e897..c908836 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -43034,1569 +43034,6 @@
       }
     ]
   },
-  "UBSanVptr Linux": {
-    "gtest_tests": [
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "absl_hardening_tests",
-        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "accessibility_unittests",
-        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
-      },
-      {
-        "args": [
-          "angle_unittests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "app_shell_unittests",
-        "test_id_prefix": "ninja://extensions/shell:app_shell_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "aura_unittests",
-        "test_id_prefix": "ninja://ui/aura:aura_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_unittests",
-        "test_id_prefix": "ninja://base:base_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_util_unittests",
-        "test_id_prefix": "ninja://base/util:base_util_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_common_unittests",
-        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_fuzzer_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_fuzzer_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_heap_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_platform_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_crypto_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_ssl_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "capture_unittests",
-        "test_id_prefix": "ninja://media/capture:capture_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cast_unittests",
-        "test_id_prefix": "ninja://media/cast:cast_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cc_unittests",
-        "test_id_prefix": "ninja://cc:cc_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_app_unittests",
-        "test_id_prefix": "ninja://chrome/test:chrome_app_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_unittests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_browsertests",
-        "test_id_prefix": "ninja://components:components_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "compositor_unittests",
-        "test_id_prefix": "ninja://ui/compositor:compositor_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_unittests",
-        "test_id_prefix": "ninja://content/test:content_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crashpad_tests",
-        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_tests",
-        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_unittests",
-        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crypto_unittests",
-        "test_id_prefix": "ninja://crypto:crypto_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "dbus_unittests",
-        "test_id_prefix": "ninja://dbus:dbus_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "device_unittests",
-        "test_id_prefix": "ninja://device:device_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "display_unittests",
-        "test_id_prefix": "ninja://ui/display:display_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "events_unittests",
-        "test_id_prefix": "ninja://ui/events:events_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_unittests",
-        "test_id_prefix": "ninja://extensions:extensions_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "filesystem_service_unittests",
-        "test_id_prefix": "ninja://components/services/filesystem:filesystem_service_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcm_unit_tests",
-        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gfx_unittests",
-        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gin_unittests",
-        "test_id_prefix": "ninja://gin:gin_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "google_apis_unittests",
-        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gpu_unittests",
-        "test_id_prefix": "ninja://gpu:gpu_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gwp_asan_unittests",
-        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_browsertests",
-        "test_id_prefix": "ninja://headless:headless_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_unittests",
-        "test_id_prefix": "ninja://headless:headless_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ipc_tests",
-        "test_id_prefix": "ninja://ipc:ipc_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "jingle_unittests",
-        "test_id_prefix": "ninja://jingle:jingle_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "latency_unittests",
-        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "libjingle_xmpp_unittests",
-        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "liburlpattern_unittests",
-        "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_blink_unittests",
-        "test_id_prefix": "ninja://media/blink:media_blink_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_unittests",
-        "test_id_prefix": "ninja://media:media_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "message_center_unittests",
-        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "midi_unittests",
-        "test_id_prefix": "ninja://media/midi:midi_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_core_unittests",
-        "test_id_prefix": "ninja://mojo/core:mojo_core_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_unittests",
-        "test_id_prefix": "ninja://mojo:mojo_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "nacl_helper_nonsfi_unittests",
-        "test_id_prefix": "ninja://components/nacl/loader:nacl_helper_nonsfi_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "nacl_loader_unittests",
-        "test_id_prefix": "ninja://components/nacl/loader:nacl_loader_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "native_theme_unittests",
-        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "net_unittests",
-        "test_id_prefix": "ninja://net:net_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "openscreen_unittests",
-        "test_id_prefix": "ninja://chrome/browser/media/router:openscreen_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "pdf_unittests",
-        "test_id_prefix": "ninja://pdf:pdf_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "perfetto_unittests",
-        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ppapi_unittests",
-        "test_id_prefix": "ninja://ppapi:ppapi_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "printing_unittests",
-        "test_id_prefix": "ninja://printing:printing_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "remoting_unittests",
-        "test_id_prefix": "ninja://remoting:remoting_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sandbox_linux_unittests",
-        "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "service_manager_unittests",
-        "test_id_prefix": "ninja://services/service_manager/tests:service_manager_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "services_unittests",
-        "test_id_prefix": "ninja://services:services_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "shell_dialogs_unittests",
-        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "skia_unittests",
-        "test_id_prefix": "ninja://skia:skia_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "snapshot_unittests",
-        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sql_unittests",
-        "test_id_prefix": "ninja://sql:sql_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "storage_unittests",
-        "test_id_prefix": "ninja://storage:storage_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sync_integration_tests",
-        "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "traffic_annotation_auditor_unittests",
-        "test_id_prefix": "ninja://tools/traffic_annotation/auditor:traffic_annotation_auditor_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_base_unittests",
-        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_touch_selection_unittests",
-        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "unit_tests",
-        "test_id_prefix": "ninja://chrome/test:unit_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "url_unittests",
-        "test_id_prefix": "ninja://url:url_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_unittests",
-        "test_id_prefix": "ninja://ui/views:views_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "viz_unittests",
-        "test_id_prefix": "ninja://components/viz:viz_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_common_unittests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_pixeltests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_browsertests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_unittests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wm_unittests",
-        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wtf_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "x11_unittests",
-        "test_id_prefix": "ninja://ui/platform_window/x11:x11_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "xr_browser_tests",
-        "test_id_prefix": "ninja://chrome/test:xr_browser_tests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "zlib_unittests",
-        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
-      }
-    ]
-  },
   "linux-win_cross-rel": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 0530321f..dfc93b04 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2078,16 +2078,6 @@
           'isolated_scripts': 'ios_clang_tot_device_tests'
         },
       },
-      'UBSanVptr Linux': {
-        'mixins': [
-          'linux-xenial',
-        ],
-        'test_suites': {
-          # no "_and_gl":gl_unittests doesn't pass yet,
-          # https://crbug.com/815183
-          'gtest_tests': 'chromium_linux_gtests',
-        },
-      },
       'linux-win_cross-rel': {
         'mixins': [
           'win10',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 06d884b..e9d7034 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1392,7 +1392,7 @@
                     "name": "Enabled_Stage2",
                     "enable_features": [
                         "AutofillEnableAccountWalletStorage",
-                        "AutofillEnablePasswordInfoBarAccountIndicationFooter"
+                        "AutofillEnableSaveCardInfoBarAccountIndicationFooter"
                     ],
                     "disable_features": [
                         "WalletRequiresFirstSyncSetupComplete"
@@ -1838,6 +1838,21 @@
             ]
         }
     ],
+    "ClipboardContextMenuNewNudgeStudy": [
+        {
+            "platforms": [
+                "chromeos"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "ClipboardHistoryContextMenuNudge"
+                    ]
+                }
+            ]
+        }
+    ],
     "CodeCacheDeduplicationStudy": [
         {
             "platforms": [
diff --git a/third_party/blink/public/common/input/pointer_id.h b/third_party/blink/public/common/input/pointer_id.h
index dc828cd..1844b9d8 100644
--- a/third_party/blink/public/common/input/pointer_id.h
+++ b/third_party/blink/public/common/input/pointer_id.h
@@ -9,8 +9,6 @@
 
 namespace blink {
 
-// TODO(tkent): Rename this to WebPointerID to follow the naming convention
-// in blink/public/.
 using PointerId = std::int32_t;
 
 }  // namespace blink
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom
index dfc7ea9..ae80513 100644
--- a/third_party/blink/public/mojom/frame/frame.mojom
+++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -113,6 +113,9 @@
 
   // Non-null when |url| is for "data:", eg. when saving an image.
   pending_remote<Blob>? data_url_blob;
+
+  // Whether the download is from context menu.
+  bool is_context_menu_save = false;
 };
 
 // Actions browser can ask renderer to perform on a Plugin.
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 86badee..00728f71 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3070,6 +3070,7 @@
   kEmbedElementWithoutTypeSrcChanged = 3749,
   kPaymentHandlerStandardizedPaymentMethodIdentifier = 3750,
   kWebCodecsAudioEncoder = 3751,
+  kEmbeddedCrossOriginFrameWithoutFrameAncestorsOrXFO = 3752,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h b/third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h
index 152758ce..c15c86bcf 100644
--- a/third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h
+++ b/third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h
@@ -56,6 +56,10 @@
   // always called at least once before OnData(), and on the same thread.
   virtual void OnSetFormat(const media::AudioParameters& params) = 0;
 
+  // Returns the number of channels preferred by the sink or -1 if
+  // unknown.
+  virtual int NumPreferredChannels() { return -1; }
+
  protected:
   ~WebMediaStreamAudioSink() override {}
 };
diff --git a/third_party/blink/public/web/OWNERS b/third_party/blink/public/web/OWNERS
index fff2ec3..5dff49dd 100644
--- a/third_party/blink/public/web/OWNERS
+++ b/third_party/blink/public/web/OWNERS
@@ -1,7 +1,7 @@
-per-file web_ax_enums.h=dmazzoni@chromium.org
-per-file web_ax_enums.h=aboxhall@chromium.org
+# Accessibility
+per-file web_ax_object.h=file://third_party/blink/renderer/modules/accessibility/OWNERS
+per-file web_ax_enums.h=file://third_party/blink/renderer/modules/accessibility/OWNERS
 per-file web_ax_enums.h=dtseng@chromium.org
-per-file web_ax_enums.h=nektar@chromium.org
 
 # Page load metrics
 per-file web_performance.h=bmcquade@chromium.org
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 3cd250ac..cf1682c4 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -299,8 +299,12 @@
 }
 
 bool Animation::Limited(base::Optional<double> current_time) const {
+  if (!current_time)
+    return false;
+
   return (EffectivePlaybackRate() < 0 && current_time <= 0) ||
-         (EffectivePlaybackRate() > 0 && current_time >= EffectEnd());
+         (EffectivePlaybackRate() > 0 &&
+          GreaterThanOrEqualToWithinEpsilon(current_time.value(), EffectEnd()));
 }
 
 Document* Animation::GetDocument() const {
diff --git a/third_party/blink/renderer/core/animation/timing_calculations.h b/third_party/blink/renderer/core/animation/timing_calculations.h
index b1ca293..2173cc7 100644
--- a/third_party/blink/renderer/core/animation/timing_calculations.h
+++ b/third_party/blink/renderer/core/animation/timing_calculations.h
@@ -56,10 +56,14 @@
   return std::abs(a - b) <= TimingCalculationEpsilon();
 }
 
-inline bool LessThanOrEqualToWithinEpsilon(double a, double b) {
+static inline bool LessThanOrEqualToWithinEpsilon(double a, double b) {
   return a <= b + TimingCalculationEpsilon();
 }
 
+static inline bool GreaterThanOrEqualToWithinEpsilon(double a, double b) {
+  return a >= b - TimingCalculationEpsilon();
+}
+
 static inline double MultiplyZeroAlwaysGivesZero(double x, double y) {
   DCHECK(!std::isnan(x));
   DCHECK(!std::isnan(y));
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index 896b68a2..0eaf436 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -3746,13 +3746,18 @@
 
 TEST_F(StyleEngineTest, UpdateStyleAndLayoutTreeForContainer) {
   GetDocument().body()->setInnerHTML(R"HTML(
-    <div id="container1" style="contain:layout">
+    <style>
+      .container {
+        contain: layout size;
+      }
+    </style>
+    <div id="container1" class="container">
       <span class="affected"></span>
-      <div id="container2" style="contain:layout" class="affected">
+      <div id="container2" class="container affected">
         <span class="affected"></span>
         <span></span>
         <span class="affected"></span>
-        <span></span>
+        <span><span class="affected"></span></span>
         <span class="affected"></span>
         <div style="display:none" class="affected">
           <span class="affected"></span>
@@ -3763,10 +3768,13 @@
         </div>
       </div>
       <span></span>
-      <div id="container3" style="contain:layout">
+      <div class="container">
         <span class="affected"></span>
         <span class="affected"></span>
       </div>
+      <span class="container" style="display:inline-block">
+        <span class="affected"></span>
+      </span>
     </div>
   )HTML");
 
@@ -3790,12 +3798,61 @@
   GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container2);
 
   // Three direct span.affected children, and the two display:none elements.
-  EXPECT_EQ(5u, GetStyleEngine().StyleForElementCount() - start_count);
+  EXPECT_EQ(6u, GetStyleEngine().StyleForElementCount() - start_count);
+}
+
+TEST_F(StyleEngineTest, ContainerQueriesContainmentNotApplying) {
+  GetDocument().body()->setInnerHTML(R"HTML(
+    <style>
+      .container {
+        contain: layout size;
+      }
+    </style>
+    <div id="container" class="container">
+      <div class="container" style="display:contents">
+        <span class="affected"></span>
+      </div>
+      <span class="container">
+        <span class="affected"></span>
+      </span>
+      <rt class="container">
+        <span class="affected"></span>
+      </rt>
+      <div class="container" style="display:table">
+        <span class="affected"></span>
+      </div>
+      <div class="container" style="display:table-cell">
+        <span class="affected"></span>
+      </div>
+      <div class="container" style="display:table-row">
+        <span class="affected"></span>
+      </div>
+      <div class="container" style="display:table-row-group">
+        <span class="affected"></span>
+      </div>
+    </div>
+  )HTML");
+
+  UpdateAllLifecyclePhases();
+
+  auto* container = GetDocument().getElementById("container");
+  auto* affected = GetDocument().getElementsByClassName("affected");
+  ASSERT_TRUE(container);
+  ASSERT_TRUE(affected);
+  SetDependsOnContainerQueries(*affected);
+
+  unsigned start_count = GetStyleEngine().StyleForElementCount();
+  GetStyleEngine().UpdateStyleAndLayoutTreeForContainer(*container);
+
+  // span.affected is updated because containment does not apply to the display
+  // types on the element styled with containment. All marked as affected are
+  // recalculated.
+  EXPECT_EQ(7u, GetStyleEngine().StyleForElementCount() - start_count);
 }
 
 TEST_F(StyleEngineTest, MarkStyleDirtyFromContainerRecalc) {
   GetDocument().body()->setInnerHTML(R"HTML(
-    <div id="container" style="contain:layout">
+    <div id="container" style="contain: layout size">
       <input id="input" type="text" class="affected">
     </div>
   )HTML");
diff --git a/third_party/blink/renderer/core/css/style_recalc.cc b/third_party/blink/renderer/core/css/style_recalc.cc
index 1c6a42c..6f22ad2 100644
--- a/third_party/blink/renderer/core/css/style_recalc.cc
+++ b/third_party/blink/renderer/core/css/style_recalc.cc
@@ -19,7 +19,8 @@
 }
 
 bool StyleRecalcChange::TraverseChild(const Node& node) const {
-  return ShouldRecalcStyleFor(node) || node.ChildNeedsStyleRecalc();
+  return ShouldRecalcStyleFor(node) || node.ChildNeedsStyleRecalc() ||
+         RecalcContainerQueryDependent();
 }
 
 bool StyleRecalcChange::ShouldRecalcStyleFor(const Node& node) const {
@@ -60,8 +61,9 @@
   // recalculating container queries. If the queries for this container also
   // changes, we will enter another container query recalc for this subtree from
   // layout.
-  const ComputedStyle* style = element.GetComputedStyle();
-  return style && !style->IsContainerForContainerQueries();
+  if (LayoutObject* layout_object = element.GetLayoutObject())
+    return !layout_object->IsContainerForContainerQueries();
+  return true;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index a49a490..68688f0 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3402,6 +3402,9 @@
 }
 
 void WebViewImpl::ApplyViewportChanges(const ApplyViewportChangesArgs& args) {
+  // TODO(https://crbug.com/1160652): Figure out if Page is null.
+  CHECK(page_);
+
   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
 
   // Store the desired offsets the visual viewport before setting the top
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index e3af04e..c4d167e 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -3026,6 +3026,7 @@
     return;
 
   auto params = mojom::blink::DownloadURLParams::New();
+  params->is_context_menu_save = true;
   params->data_url_blob = DataURLToBlob(url);
   GetLocalFrameHostRemote().DownloadURL(std::move(params));
 }
diff --git a/third_party/blink/renderer/core/html/conversion_measurement_parsing.cc b/third_party/blink/renderer/core/html/conversion_measurement_parsing.cc
index f2a1eb8..a2165c74 100644
--- a/third_party/blink/renderer/core/html/conversion_measurement_parsing.cc
+++ b/third_party/blink/renderer/core/html/conversion_measurement_parsing.cc
@@ -72,7 +72,7 @@
 
   bool impression_data_is_valid = false;
   uint64_t impression_data =
-      impression_data_string.HexToUInt64Strict(&impression_data_is_valid);
+      impression_data_string.ToUInt64Strict(&impression_data_is_valid);
 
   // Provide a default of 0 if the impression data was not valid.
   impression_data = impression_data_is_valid ? impression_data : 0UL;
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc
index 9f34353..ee21abd 100644
--- a/third_party/blink/renderer/core/input/event_handler.cc
+++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -300,8 +300,10 @@
   AutoscrollController* controller = scroll_manager_->GetAutoscrollController();
   if (!controller)
     return;
+
   LayoutBox* scrollable = LayoutBox::FindAutoscrollable(
       layout_object, /*is_middle_click_autoscroll*/ true);
+
   controller->StartMiddleClickAutoscroll(
       layout_object->GetFrame(), scrollable,
       LastKnownMousePositionInRootFrame(),
diff --git a/third_party/blink/renderer/core/input/scroll_manager.cc b/third_party/blink/renderer/core/input/scroll_manager.cc
index 8fb4fb4..03f663a 100644
--- a/third_party/blink/renderer/core/input/scroll_manager.cc
+++ b/third_party/blink/renderer/core/input/scroll_manager.cc
@@ -133,8 +133,20 @@
   return nullptr;
 }
 
-static bool CanPropagate(const ScrollState& scroll_state, const Node& node) {
-  ScrollableArea* scrollable_area = node.GetLayoutBox()->GetScrollableArea();
+ScrollPropagationDirection ScrollManager::ComputePropagationDirection(
+    const ScrollState& scroll_state) {
+  if (scroll_state.deltaXHint() == 0 && scroll_state.deltaYHint() != 0)
+    return ScrollPropagationDirection::kVertical;
+  if (scroll_state.deltaXHint() != 0 && scroll_state.deltaYHint() == 0)
+    return ScrollPropagationDirection::kHorizontal;
+  if (scroll_state.deltaXHint() != 0 && scroll_state.deltaYHint() != 0)
+    return ScrollPropagationDirection::kBoth;
+  return ScrollPropagationDirection::kNone;
+}
+
+bool ScrollManager::CanPropagate(const LayoutBox* layout_box,
+                                 ScrollPropagationDirection direction) {
+  ScrollableArea* scrollable_area = layout_box->GetScrollableArea();
   if (!scrollable_area)
     return true;
 
@@ -142,54 +154,106 @@
       !scrollable_area->UserInputScrollable(kVerticalScrollbar))
     return true;
 
-  return (scroll_state.deltaXHint() == 0 ||
-          node.GetComputedStyle()->OverscrollBehaviorX() ==
-              EOverscrollBehavior::kAuto) &&
-         (scroll_state.deltaYHint() == 0 ||
-          node.GetComputedStyle()->OverscrollBehaviorY() ==
-              EOverscrollBehavior::kAuto);
+  switch (direction) {
+    case ScrollPropagationDirection::kBoth:
+      return ((layout_box->StyleRef().OverscrollBehaviorX() ==
+               EOverscrollBehavior::kAuto) &&
+              (layout_box->StyleRef().OverscrollBehaviorY() ==
+               EOverscrollBehavior::kAuto));
+    case ScrollPropagationDirection::kVertical:
+      return layout_box->StyleRef().OverscrollBehaviorY() ==
+             EOverscrollBehavior::kAuto;
+    case ScrollPropagationDirection::kHorizontal:
+      return layout_box->StyleRef().OverscrollBehaviorX() ==
+             EOverscrollBehavior::kAuto;
+    case ScrollPropagationDirection::kNone:
+      return true;
+    default:
+      NOTREACHED();
+  }
 }
 
 void ScrollManager::RecomputeScrollChain(const Node& start_node,
                                          const ScrollState& scroll_state,
-                                         Deque<DOMNodeId>& scroll_chain) {
+                                         Deque<DOMNodeId>& scroll_chain,
+                                         bool is_autoscroll) {
   DCHECK(scroll_chain.IsEmpty());
   scroll_chain.clear();
 
   DCHECK(start_node.GetLayoutObject());
-  LayoutBox* cur_box = start_node.GetLayoutObject()->EnclosingBox();
 
-  // Scrolling propagates along the containing block chain and ends at the
-  // RootScroller node. The RootScroller node will have a custom applyScroll
-  // callback that performs scrolling as well as associated "root" actions like
-  // browser control movement and overscroll glow.
-  while (cur_box) {
-    Node* cur_node = cur_box->GetNode();
+  if (is_autoscroll) {
+    // Propagate the autoscroll along the layout object chain, and
+    // append only the first node which is able to consume the scroll delta.
+    // The scroll node is computed differently to regular scrolls in order to
+    // maintain consistency with the autoscroll controller.
+    LayoutBox* autoscrollable = LayoutBox::FindAutoscrollable(
+        start_node.GetLayoutObject(), is_autoscroll);
+    if (autoscrollable) {
+      Node* cur_node = autoscrollable->GetNode();
+      LayoutObject* layout_object = cur_node->GetLayoutObject();
+      while (layout_object &&
+             !CanScroll(scroll_state, *cur_node, is_autoscroll)) {
+        ScrollPropagationDirection direction =
+            ComputePropagationDirection(scroll_state);
 
-    if (cur_node) {
-      if (CanScroll(scroll_state, *cur_node))
-        scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
+        if (!CanPropagate(cur_node->GetLayoutBox(), direction))
+          break;
 
-      if (cur_node->IsEffectiveRootScroller())
-        break;
-
-      if (!CanPropagate(scroll_state, *cur_node)) {
-        // We should add the first node with non-auto overscroll-behavior to
-        // the scroll chain regardlessly, as it's the only node we can latch to.
-        if (scroll_chain.empty() ||
-            scroll_chain.front() != DOMNodeIds::IdForNode(cur_node)) {
-          scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
+        if (!layout_object->Parent() &&
+            layout_object->GetNode() == layout_object->GetDocument() &&
+            layout_object->GetDocument().LocalOwner()) {
+          layout_object =
+              layout_object->GetDocument().LocalOwner()->GetLayoutObject();
+        } else {
+          layout_object = layout_object->Parent();
         }
-        break;
+        LayoutBox* new_autoscrollable =
+            LayoutBox::FindAutoscrollable(layout_object, is_autoscroll);
+        if (new_autoscrollable)
+          cur_node = new_autoscrollable->GetNode();
       }
+      scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
     }
+  } else {
+    LayoutBox* cur_box = start_node.GetLayoutObject()->EnclosingBox();
 
-    cur_box = cur_box->ContainingBlock();
+    // Scrolling propagates along the containing block chain and ends at the
+    // RootScroller node. The RootScroller node will have a custom applyScroll
+    // callback that performs scrolling as well as associated "root" actions
+    // like browser control movement and overscroll glow.
+    while (cur_box) {
+      Node* cur_node = cur_box->GetNode();
+
+      if (cur_node) {
+        if (CanScroll(scroll_state, *cur_node, /* for_autoscroll */ false))
+          scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
+
+        if (cur_node->IsEffectiveRootScroller())
+          break;
+
+        ScrollPropagationDirection direction =
+            ComputePropagationDirection(scroll_state);
+        if (!CanPropagate(cur_node->GetLayoutBox(), direction)) {
+          // We should add the first node with non-auto overscroll-behavior to
+          // the scroll chain regardlessly, as it's the only node we can latch
+          // to.
+          if (scroll_chain.empty() ||
+              scroll_chain.front() != DOMNodeIds::IdForNode(cur_node)) {
+            scroll_chain.push_front(DOMNodeIds::IdForNode(cur_node));
+          }
+          break;
+        }
+      }
+
+      cur_box = cur_box->ContainingBlock();
+    }
   }
 }
 
 bool ScrollManager::CanScroll(const ScrollState& scroll_state,
-                              const Node& current_node) {
+                              const Node& current_node,
+                              bool for_autoscroll) {
   LayoutBox* scrolling_box = current_node.GetLayoutBox();
   if (auto* element = DynamicTo<Element>(current_node))
     scrolling_box = element->GetLayoutBoxForScrolling();
@@ -198,8 +262,9 @@
 
   // We need to always add the global root scroller even if it isn't scrollable
   // since we can always pinch-zoom and scroll as well as for overscroll
-  // effects.
-  if (scrolling_box->IsGlobalRootScroller())
+  // effects. If autoscrolling, ignore this condition because we latch on
+  // to the deepest autoscrollable node.
+  if (scrolling_box->IsGlobalRootScroller() && !for_autoscroll)
     return true;
 
   // If this is the main LayoutView, and it's not the root scroller, that means
@@ -207,9 +272,10 @@
   // scroll the LayoutView should cause panning of the visual viewport as well
   // so ensure it gets added to the scroll chain. See LTHI::ApplyScroll for the
   // equivalent behavior in CC. Node::NativeApplyScroll contains a special
-  // handler for this case.
+  // handler for this case. If autoscrolling, ignore this condition because we
+  // latch on to the deepest autoscrollable node.
   if (IsA<LayoutView>(scrolling_box) &&
-      current_node.GetDocument().GetFrame()->IsMainFrame()) {
+      current_node.GetDocument().GetFrame()->IsMainFrame() && !for_autoscroll) {
     return true;
   }
 
@@ -273,7 +339,8 @@
       std::make_unique<ScrollStateData>();
   auto* scroll_state =
       MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
-  RecomputeScrollChain(*node, *scroll_state, scroll_chain);
+  RecomputeScrollChain(*node, *scroll_state, scroll_chain,
+                       /* is_autoscroll */ false);
 
   while (!scroll_chain.IsEmpty()) {
     Node* scroll_chain_node = DOMNodeIds::NodeForId(scroll_chain.TakeLast());
@@ -497,21 +564,11 @@
       delta_consumed_for_scroll_sequence_;
   auto* scroll_state =
       MakeGarbageCollected<ScrollState>(std::move(scroll_state_data));
-  // For middle click autoscroll, only scrollable area for
-  // |scroll_gesture_handling_node_| should receive and handle all scroll
-  // events. It should not bubble up to the ancestor.
-  if (gesture_event.SourceDevice() == WebGestureDevice::kSyntheticAutoscroll) {
-    LayoutBox* scrollable = LayoutBox::FindAutoscrollable(
-        scroll_gesture_handling_node_->GetLayoutObject(),
-        /*is_middle_click_autoscroll*/ true);
-    if (scrollable) {
-      Node* scrollable_node = scrollable->GetNode();
-      current_scroll_chain_.push_back(DOMNodeIds::IdForNode(scrollable_node));
-    }
-  } else {
-    RecomputeScrollChain(*scroll_gesture_handling_node_.Get(), *scroll_state,
-                         current_scroll_chain_);
-  }
+
+  RecomputeScrollChain(
+      *scroll_gesture_handling_node_.Get(), *scroll_state,
+      current_scroll_chain_,
+      gesture_event.SourceDevice() == WebGestureDevice::kSyntheticAutoscroll);
 
   TRACE_EVENT_INSTANT1("input", "Computed Scroll Chain",
                        TRACE_EVENT_SCOPE_THREAD, "length",
diff --git a/third_party/blink/renderer/core/input/scroll_manager.h b/third_party/blink/renderer/core/input/scroll_manager.h
index dd372e74..7ea7463 100644
--- a/third_party/blink/renderer/core/input/scroll_manager.h
+++ b/third_party/blink/renderer/core/input/scroll_manager.h
@@ -34,6 +34,10 @@
 class ScrollState;
 class WebGestureEvent;
 
+// Scroll directions used to check whether propagation is possible in a given
+// direction. Used in CanPropagate.
+enum class ScrollPropagationDirection { kHorizontal, kVertical, kBoth, kNone };
+
 // This class takes care of scrolling and resizing and the related states. The
 // user action that causes scrolling or resizing is determined in other *Manager
 // classes and they call into this class for doing the work.
@@ -108,6 +112,13 @@
 
   void AnimateSnapFling(base::TimeTicks monotonic_time);
 
+  // Determines whether the scroll-chain should be propagated upwards given a
+  // scroll direction.
+  static bool CanPropagate(const LayoutBox* layout_box,
+                           ScrollPropagationDirection direction);
+  static ScrollPropagationDirection ComputePropagationDirection(
+      const ScrollState&);
+
  private:
   Node* NodeTargetForScrollableAreaElementId(
       CompositorElementId scrollable_area_element_id) const;
@@ -133,8 +144,11 @@
 
   void RecomputeScrollChain(const Node& start_node,
                             const ScrollState&,
-                            Deque<DOMNodeId>& scroll_chain);
-  bool CanScroll(const ScrollState&, const Node& current_node);
+                            Deque<DOMNodeId>& scroll_chain,
+                            bool is_autoscroll);
+  bool CanScroll(const ScrollState&,
+                 const Node& current_node,
+                 bool for_autoscroll);
 
   // scroller_size is set only when scrolling non root scroller.
   void ComputeScrollRelatedMetrics(
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 79a3bd65..f84ee85 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -1989,7 +1989,8 @@
 
 MinMaxSizes LayoutBox::IntrinsicLogicalWidths(MinMaxSizesType type) const {
   NOT_DESTROYED();
-  if (type == MinMaxSizesType::kContent && !StyleRef().AspectRatio().IsAuto()) {
+  if (!ShouldComputeSizeAsReplaced() && type == MinMaxSizesType::kContent &&
+      !StyleRef().AspectRatio().IsAuto()) {
     MinMaxSizes sizes;
     if (ComputeLogicalWidthFromAspectRatio(&sizes.min_size)) {
       sizes.max_size = sizes.min_size;
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 7903e2d..7df196b 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -625,6 +625,10 @@
     return ShouldApplyPaintContainment() && ShouldApplyLayoutContainment() &&
            ShouldApplySizeContainment();
   }
+  inline bool IsContainerForContainerQueries() const {
+    NOT_DESTROYED();
+    return ShouldApplyLayoutContainment() && ShouldApplySizeContainment();
+  }
 
   inline bool IsStackingContext() const {
     NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/loader/empty_clients.cc b/third_party/blink/renderer/core/loader/empty_clients.cc
index 1627238..8b975c20a 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.cc
+++ b/third_party/blink/renderer/core/loader/empty_clients.cc
@@ -184,6 +184,4 @@
   return nullptr;
 }
 
-EmptyRemoteFrameClient::EmptyRemoteFrameClient() = default;
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index f380e39..fe5aeef 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -400,37 +400,6 @@
   DISALLOW_COPY_AND_ASSIGN(EmptySpellCheckPanelHostClient);
 };
 
-class CORE_EXPORT EmptyRemoteFrameClient : public RemoteFrameClient {
- public:
-  EmptyRemoteFrameClient();
-
-  // RemoteFrameClient implementation.
-  void Navigate(const ResourceRequest&,
-                blink::WebLocalFrame* initiator_frame,
-                bool should_replace_current_entry,
-                bool is_opener_navigation,
-                bool initiator_frame_has_download_sandbox_flag,
-                bool initiator_frame_is_ad,
-                mojo::PendingRemote<mojom::blink::BlobURLToken>,
-                const base::Optional<WebImpression>&) override {}
-  unsigned BackForwardLength() override { return 0; }
-  void FrameRectsChanged(const IntRect& local_frame_rect,
-                         const IntRect& transformed_frame_rect) override {}
-  void SynchronizeVisualProperties() override {}
-  AssociatedInterfaceProvider* GetRemoteAssociatedInterfaces() override {
-    return AssociatedInterfaceProvider::GetEmptyAssociatedInterfaceProvider();
-  }
-
-  // FrameClient implementation.
-  bool InShadowTree() const override { return false; }
-  void Detached(FrameDetachType) override {}
-  base::UnguessableToken GetDevToolsFrameToken() const override {
-    return base::UnguessableToken::Create();
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(EmptyRemoteFrameClient);
-};
-
 CORE_EXPORT void FillWithEmptyClients(Page::PageClients&);
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/autoscroll_controller.cc b/third_party/blink/renderer/core/page/autoscroll_controller.cc
index 84e4f01..d1dc0dc 100644
--- a/third_party/blink/renderer/core/page/autoscroll_controller.cc
+++ b/third_party/blink/renderer/core/page/autoscroll_controller.cc
@@ -29,11 +29,13 @@
 
 #include "third_party/blink/renderer/core/page/autoscroll_controller.h"
 
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
 #include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/input/scroll_manager.h"
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -143,6 +145,18 @@
   if (pressed_layout_object_ == layout_object)
     pressed_layout_object_ = nullptr;
 
+  if (horizontal_autoscroll_layout_box_ == layout_object)
+    horizontal_autoscroll_layout_box_ = nullptr;
+
+  if (vertical_autoscroll_layout_box_ == layout_object)
+    vertical_autoscroll_layout_box_ = nullptr;
+
+  if (MiddleClickAutoscrollInProgress() && !horizontal_autoscroll_layout_box_ &&
+      !vertical_autoscroll_layout_box_) {
+    page_->GetChromeClient().AutoscrollEnd(layout_object->GetFrame());
+    autoscroll_type_ = kNoAutoscroll;
+  }
+
   if (autoscroll_layout_object_ != layout_object)
     return;
   autoscroll_layout_object_ = nullptr;
@@ -250,7 +264,16 @@
   if (!MiddleClickAutoscrollInProgress())
     return;
 
-  if (!autoscroll_layout_object_->CanBeScrolledAndHasScrollableArea()) {
+  bool horizontal_autoscroll_possible =
+      horizontal_autoscroll_layout_box_ &&
+      horizontal_autoscroll_layout_box_->GetNode();
+  bool vertical_autoscroll_possible =
+      vertical_autoscroll_layout_box_ &&
+      vertical_autoscroll_layout_box_->GetNode();
+  if (horizontal_autoscroll_possible &&
+      !horizontal_autoscroll_layout_box_->CanBeScrolledAndHasScrollableArea() &&
+      vertical_autoscroll_possible &&
+      !vertical_autoscroll_layout_box_->CanBeScrolledAndHasScrollableArea()) {
     StopMiddleClickAutoscroll(frame);
     return;
   }
@@ -277,11 +300,17 @@
       pow(fabs(distance.Height()), kExponent) * kMultiplier * y_signum);
 
   bool can_scroll_vertically =
-      CanScrollDirection(autoscroll_layout_object_, frame->GetPage(),
-                         ScrollOrientation::kVerticalScroll);
+      vertical_autoscroll_possible
+          ? CanScrollDirection(vertical_autoscroll_layout_box_,
+                               frame->GetPage(),
+                               ScrollOrientation::kVerticalScroll)
+          : false;
   bool can_scroll_horizontally =
-      CanScrollDirection(autoscroll_layout_object_, frame->GetPage(),
-                         ScrollOrientation::kHorizontalScroll);
+      horizontal_autoscroll_possible
+          ? CanScrollDirection(horizontal_autoscroll_layout_box_,
+                               frame->GetPage(),
+                               ScrollOrientation::kHorizontalScroll)
+          : false;
 
   if (velocity != last_velocity_) {
     last_velocity_ = velocity;
@@ -319,7 +348,8 @@
   autoscroll_type_ = kNoAutoscroll;
   page_->GetChromeClient().SetCursorOverridden(false);
   frame->LocalFrameRoot().GetEventHandler().UpdateCursor();
-  autoscroll_layout_object_ = nullptr;
+  horizontal_autoscroll_layout_box_ = nullptr;
+  vertical_autoscroll_layout_box_ = nullptr;
 }
 
 bool AutoscrollController::MiddleClickAutoscrollInProgress() const {
@@ -338,17 +368,68 @@
   if (autoscroll_type_ != kNoAutoscroll)
     return;
 
-  autoscroll_layout_object_ = scrollable;
   autoscroll_type_ = kAutoscrollForMiddleClick;
   middle_click_mode_ = kMiddleClickInitial;
   middle_click_autoscroll_start_pos_global_ = position_global;
 
-  bool can_scroll_vertically =
-      CanScrollDirection(autoscroll_layout_object_, frame->GetPage(),
-                         ScrollOrientation::kVerticalScroll);
-  bool can_scroll_horizontally =
-      CanScrollDirection(autoscroll_layout_object_, frame->GetPage(),
-                         ScrollOrientation::kHorizontalScroll);
+  bool can_scroll_vertically = false;
+  bool can_scroll_horizontally = false;
+
+  // Scroll propagation can be prevented in either direction independently.
+  // We check whether autoscroll can be prevented in either direction after
+  // checking whether the layout box can be scrolled. If propagation is not
+  // allowed, we do not perform further checks for whether parents can be
+  // scrolled in that direction.
+  bool can_propagate_vertically = true;
+  bool can_propagate_horizontally = true;
+
+  LayoutObject* layout_object = scrollable->GetNode()->GetLayoutObject();
+
+  while (layout_object && !(can_scroll_horizontally && can_scroll_vertically)) {
+    LayoutBox* layout_box;
+
+    if (layout_object->IsBox()) {
+      layout_box = To<LayoutBox>(layout_object);
+      // Check whether the layout box can be scrolled and has horizontal
+      // scrollable area.
+      if (can_propagate_vertically &&
+          CanScrollDirection(layout_box, frame->GetPage(),
+                             ScrollOrientation::kVerticalScroll) &&
+          !vertical_autoscroll_layout_box_) {
+        vertical_autoscroll_layout_box_ = layout_box;
+        can_scroll_vertically = true;
+      }
+      // Check whether the layout box can be scrolled and has vertical
+      // scrollable area.
+      if (can_propagate_horizontally &&
+          CanScrollDirection(layout_box, frame->GetPage(),
+                             ScrollOrientation::kHorizontalScroll) &&
+          !horizontal_autoscroll_layout_box_) {
+        horizontal_autoscroll_layout_box_ = layout_box;
+        can_scroll_horizontally = true;
+      }
+    }
+
+    can_propagate_vertically = ScrollManager::CanPropagate(
+        layout_box, ScrollPropagationDirection::kVertical);
+    can_propagate_horizontally = ScrollManager::CanPropagate(
+        layout_box, ScrollPropagationDirection::kHorizontal);
+
+    // Exit loop if we can't propagate to the parent in any direction or if
+    // layout boxes have been found for both directions.
+    if ((!can_propagate_vertically && !can_propagate_horizontally) ||
+        (can_scroll_horizontally && can_scroll_vertically))
+      break;
+
+    if (!layout_object->Parent() &&
+        layout_object->GetNode() == layout_object->GetDocument() &&
+        layout_object->GetDocument().LocalOwner()) {
+      layout_object =
+          layout_object->GetDocument().LocalOwner()->GetLayoutObject();
+    } else {
+      layout_object = layout_object->Parent();
+    }
+  }
 
   UseCounter::Count(frame->GetDocument(),
                     WebFeature::kMiddleClickAutoscrollStart);
diff --git a/third_party/blink/renderer/core/page/autoscroll_controller.h b/third_party/blink/renderer/core/page/autoscroll_controller.h
index 7e04c41..0b0a711 100644
--- a/third_party/blink/renderer/core/page/autoscroll_controller.h
+++ b/third_party/blink/renderer/core/page/autoscroll_controller.h
@@ -84,7 +84,7 @@
 
   // Middle-click autoscroll.
   void StartMiddleClickAutoscroll(LocalFrame*,
-                                  LayoutBox*,
+                                  LayoutBox* scrollable,
                                   const FloatPoint& position,
                                   const FloatPoint& position_global);
   void HandleMouseMoveForMiddleClickAutoscroll(
@@ -102,15 +102,17 @@
 
   Member<Page> page_;
   AutoscrollType autoscroll_type_ = kNoAutoscroll;
-  LayoutBox* autoscroll_layout_object_ = nullptr;
 
   // Selection and drag-and-drop autoscroll.
   void ScheduleMainThreadAnimation();
+  LayoutBox* autoscroll_layout_object_ = nullptr;
   LayoutBox* pressed_layout_object_ = nullptr;
   PhysicalOffset drag_and_drop_autoscroll_reference_position_;
   base::TimeTicks drag_and_drop_autoscroll_start_time_;
 
   // Middle-click autoscroll.
+  LayoutBox* horizontal_autoscroll_layout_box_ = nullptr;
+  LayoutBox* vertical_autoscroll_layout_box_ = nullptr;
   FloatPoint middle_click_autoscroll_start_pos_global_;
   gfx::Vector2dF last_velocity_;
   MiddleClickMode middle_click_mode_ = kMiddleClickInitial;
@@ -120,6 +122,9 @@
   FRIEND_TEST_ALL_PREFIXES(AutoscrollControllerTest,
                            ContinueAutoscrollAfterMouseLeaveEvent);
   FRIEND_TEST_ALL_PREFIXES(AutoscrollControllerTest, StopAutoscrollOnResize);
+  FRIEND_TEST_ALL_PREFIXES(AutoscrollControllerTest, AutoscrollIsNotPropagated);
+  FRIEND_TEST_ALL_PREFIXES(AutoscrollControllerTest,
+                           AutoscrollIsPropagatedInYDirection);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/autoscroll_controller_test.cc b/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
index d24da0e..ddd6816 100644
--- a/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
+++ b/third_party/blink/renderer/core/page/autoscroll_controller_test.cc
@@ -182,4 +182,102 @@
   EXPECT_TRUE(controller.IsAutoscrolling());
 }
 
+// Ensure that middle click autoscroll is not propagated in a direction when
+// propagation is not allowed.
+TEST_F(AutoscrollControllerTest, AutoscrollIsNotPropagated) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <html>
+      <head>
+        <style>
+          #scrollable {
+            width: 820px;
+            height: 620px;
+            overflow: auto;
+            overscroll-behavior: contain;
+          }
+          #inner {
+            width: 2500px;
+            background-color: aqua;
+            height: 100px;
+          }
+        </style>
+      </head>
+      <body style='width: 3000px; height: 3000px;'>
+        <div id="scrollable">
+          <div id="inner"></div>
+        </div>
+      </body>
+    </html>
+  )HTML");
+
+  Compositor().BeginFrame();
+
+  AutoscrollController& controller = GetAutoscrollController();
+
+  EXPECT_FALSE(controller.IsAutoscrolling());
+
+  LocalFrame* frame = GetDocument().GetFrame();
+  LayoutBox* scrollable =
+      GetDocument().getElementById("scrollable")->GetLayoutBox();
+
+  controller.StartMiddleClickAutoscroll(
+      frame, scrollable, FloatPoint(15.0, 15.0), FloatPoint(15.0, 15.0));
+
+  EXPECT_TRUE(controller.IsAutoscrolling());
+  EXPECT_TRUE(controller.horizontal_autoscroll_layout_box_);
+  EXPECT_FALSE(controller.vertical_autoscroll_layout_box_);
+}
+
+// Ensure that middle click autoscroll is propagated in a direction when
+// overscroll-behavior is set to auto for a that direction.
+TEST_F(AutoscrollControllerTest, AutoscrollIsPropagatedInYDirection) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <html>
+      <head>
+        <style>
+          #scrollable {
+            width: 820px;
+            height: 620px;
+            overflow: auto;
+            overscroll-behavior-x: contain;
+          }
+          #inner {
+            width: 1000px;
+            background-color: aqua;
+            height: 100px;
+          }
+        </style>
+      </head>
+      <body style='width: 3000px; height: 3000px;'>
+        <div id="scrollable">
+          <div id="inner"></div>
+        </div>
+      </body>
+    </html>
+  )HTML");
+
+  Compositor().BeginFrame();
+
+  AutoscrollController& controller = GetAutoscrollController();
+
+  EXPECT_FALSE(controller.IsAutoscrolling());
+
+  LocalFrame* frame = GetDocument().GetFrame();
+  LayoutBox* scrollable =
+      GetDocument().getElementById("scrollable")->GetLayoutBox();
+
+  controller.StartMiddleClickAutoscroll(
+      frame, scrollable, FloatPoint(15.0, 15.0), FloatPoint(15.0, 15.0));
+
+  EXPECT_TRUE(controller.IsAutoscrolling());
+  EXPECT_TRUE(controller.vertical_autoscroll_layout_box_);
+  EXPECT_TRUE(controller.horizontal_autoscroll_layout_box_);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.cc b/third_party/blink/renderer/core/paint/box_painter_base.cc
index 0d26ffb..e483f91 100644
--- a/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -59,6 +59,24 @@
     context.EndLayer();
 }
 
+namespace {
+
+void ApplySpreadToShadowShape(FloatRoundedRect& shadow_shape, float spread) {
+  if (spread == 0)
+    return;
+
+  if (spread >= 0)
+    shadow_shape.ExpandRadii(spread);
+  else
+    shadow_shape.ShrinkRadii(-spread);
+
+  if (!shadow_shape.IsRenderable())
+    shadow_shape.AdjustRadii();
+  shadow_shape.ConstrainRadii();
+}
+
+}  // namespace
+
 void BoxPainterBase::PaintNormalBoxShadow(const PaintInfo& info,
                                           const PhysicalRect& paint_rect,
                                           const ComputedStyle& style,
@@ -147,14 +165,7 @@
     if (has_border_radius) {
       FloatRoundedRect rounded_fill_rect = border;
       rounded_fill_rect.Inflate(shadow_spread);
-
-      if (shadow_spread >= 0)
-        rounded_fill_rect.ExpandRadii(shadow_spread);
-      else
-        rounded_fill_rect.ShrinkRadii(-shadow_spread);
-      if (!rounded_fill_rect.IsRenderable())
-        rounded_fill_rect.AdjustRadii();
-      rounded_fill_rect.ConstrainRadii();
+      ApplySpreadToShadowShape(rounded_fill_rect, shadow_spread);
       context.FillRoundedRect(rounded_fill_rect, Color::kBlack);
     } else {
       context.FillRect(fill_rect, Color::kBlack);
@@ -255,10 +266,7 @@
     GraphicsContextStateSaver state_saver(context);
     if (bounds.IsRounded()) {
       context.ClipRoundedRect(bounds);
-      if (shadow.Spread() < 0)
-        inner_rounded_rect.ExpandRadii(-shadow.Spread());
-      else
-        inner_rounded_rect.ShrinkRadii(shadow.Spread());
+      ApplySpreadToShadowShape(inner_rounded_rect, -shadow.Spread());
     } else {
       context.Clip(bounds.Rect());
     }
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 39d7b2e1..6d8a64b 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2662,8 +2662,6 @@
     return LogicalSize(LayoutUnit(ratio.Width()), LayoutUnit(ratio.Height()));
   }
 
-  bool IsContainerForContainerQueries() const { return ContainsLayout(); }
-
  private:
   EClear Clear() const { return ClearInternal(); }
   EFloat Floating() const { return FloatingInternal(); }
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
index 9298c7f..4f66fa2 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.cc
@@ -72,7 +72,6 @@
       features::kWebRtcAllow48kHzProcessingOnArm);
 }
 
-constexpr int kAudioProcessingNumberOfChannels = 1;
 constexpr int kBuffersPerSecond = 100;  // 10 ms per buffer.
 
 }  // namespace
@@ -89,6 +88,7 @@
   MediaStreamAudioBus(int channels, int frames)
       : bus_(media::AudioBus::Create(channels, frames)),
         channel_ptrs_(new float*[channels]) {
+    bus_->Zero();
     // May be created in the main render thread and used in the audio threads.
     DETACH_FROM_THREAD(thread_checker_);
   }
@@ -288,6 +288,7 @@
 
 bool MediaStreamAudioProcessor::ProcessAndConsumeData(
     int volume,
+    int num_preferred_channels,
     bool key_pressed,
     media::AudioBus** processed_data,
     base::TimeDelta* capture_delay,
@@ -308,9 +309,10 @@
   *new_volume = 0;
   if (audio_processing_) {
     output_bus = output_bus_.get();
-    *new_volume = ProcessData(process_bus->channel_ptrs(),
-                              process_bus->bus()->frames(), *capture_delay,
-                              volume, key_pressed, output_bus->channel_ptrs());
+    *new_volume =
+        ProcessData(process_bus->channel_ptrs(), process_bus->bus()->frames(),
+                    *capture_delay, volume, key_pressed, num_preferred_channels,
+                    output_bus->channel_ptrs());
   }
 
   // Swap channels before interleaving the data.
@@ -664,26 +666,43 @@
 #endif  // BUILDFLAG(IS_CHROMECAST)
                                      : input_format.sample_rate();
 
-  media::ChannelLayout output_channel_layout;
-  if (!audio_processing_ || use_capture_multi_channel_processing_) {
-    output_channel_layout = input_format.channel_layout();
-  } else {
-    output_channel_layout =
-        media::GuessChannelLayout(kAudioProcessingNumberOfChannels);
-  }
-
   // The output channels from the fifo is normally the same as input.
   int fifo_output_channels = input_format.channels();
 
-  // Special case for if we have a keyboard mic channel on the input and no
-  // audio processing is used. We will then have the fifo strip away that
-  // channel. So we use stereo as output layout, and also change the output
-  // channels for the fifo.
-  if (input_format.channel_layout() ==
-          media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC &&
-      !audio_processing_) {
-    output_channel_layout = media::CHANNEL_LAYOUT_STEREO;
-    fifo_output_channels = ChannelLayoutToChannelCount(output_channel_layout);
+  media::ChannelLayout output_channel_layout;
+  if (!audio_processing_) {
+    if (input_format.channel_layout() ==
+        media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
+      // Special case for if we have a keyboard mic channel on the input and no
+      // audio processing is used. We will then have the fifo strip away that
+      // channel. So we use stereo as output layout, and also change the output
+      // channels for the fifo.
+      output_channel_layout = media::CHANNEL_LAYOUT_STEREO;
+      fifo_output_channels = ChannelLayoutToChannelCount(output_channel_layout);
+    } else {
+      output_channel_layout = input_format.channel_layout();
+    }
+  } else if (use_capture_multi_channel_processing_) {
+    // The number of output channels is equal to the number of input channels.
+    // If the media stream audio processor receives stereo input it will output
+    // stereo. To reduce computational complexity, APM will not perform full
+    // multichannel processing unless any sink requests more than one channel.
+    // If the input is multichannel but the sinks are not interested in more
+    // than one channel, APM will internally downmix the signal to mono and
+    // process it. The processed mono signal will then be upmixed to same number
+    // of channels as the input before leaving the media stream audio processor.
+    // If a sink later requests stereo, APM will start performing true stereo
+    // processing. There will be no need to change the output format.
+
+    // The keyboard mic channel shall not be part of the output.
+    if (input_format.channel_layout() ==
+        media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
+      output_channel_layout = media::CHANNEL_LAYOUT_STEREO;
+    } else {
+      output_channel_layout = input_format.channel_layout();
+    }
+  } else {
+    output_channel_layout = media::CHANNEL_LAYOUT_MONO;
   }
 
   // webrtc::AudioProcessing requires a 10 ms chunk size. We use this native
@@ -723,6 +742,7 @@
                                            base::TimeDelta capture_delay,
                                            int volume,
                                            bool key_pressed,
+                                           int num_preferred_channels,
                                            float* const* output_ptrs) {
   DCHECK(audio_processing_);
   DCHECK_CALLED_ON_VALID_THREAD(capture_thread_checker_);
@@ -751,14 +771,47 @@
   webrtc::AudioProcessing* ap = audio_processing_.get();
   ap->set_stream_delay_ms(total_delay_ms);
 
+  // Keep track of the maximum number of preferred channels. The number of
+  // output channels of APM can increase if preferred by the sinks, but
+  // never decrease.
+  max_num_preferred_output_channels_ =
+      std::max(max_num_preferred_output_channels_, num_preferred_channels);
+
   DCHECK_LE(volume, WebRtcAudioDeviceImpl::kMaxVolumeLevel);
   ap->set_stream_analog_level(volume);
   ap->set_stream_key_pressed(key_pressed);
 
+  // Depending on how many channels the sinks prefer, the number of APM output
+  // channels is allowed to vary between 1 and the number of channels of the
+  // output format. The output format in turn depends on the input format.
+  // Example: With a stereo mic the output format will have 2 channels, and APM
+  // will produce 1 or 2 output channels depending on the sinks.
+  int num_apm_output_channels =
+      std::min(max_num_preferred_output_channels_, output_format_.channels());
+
+  // Limit number of apm output channels to 2 to avoid potential problems with
+  // discrete channel mapping.
+  num_apm_output_channels = std::min(num_apm_output_channels, 2);
+
+  CHECK_GE(num_apm_output_channels, 1);
+  const webrtc::StreamConfig apm_output_config = webrtc::StreamConfig(
+      output_format_.sample_rate(), num_apm_output_channels, false);
+
   int err = ap->ProcessStream(process_ptrs, CreateStreamConfig(input_format_),
-                              CreateStreamConfig(output_format_), output_ptrs);
+                              apm_output_config, output_ptrs);
   DCHECK_EQ(err, 0) << "ProcessStream() error: " << err;
 
+  // Upmix if the number of channels processed by APM is less than the number
+  // specified in the output format. Channels above stereo will be set to zero.
+  if (num_apm_output_channels < output_format_.channels()) {
+    if (num_apm_output_channels == 1) {
+      // The right channel is a copy of the left channel. Remaining channels
+      // have already been set to zero at initialization.
+      memcpy(&output_ptrs[1][0], &output_ptrs[0][0],
+             output_format_.frames_per_buffer() * sizeof(output_ptrs[0][0]));
+    }
+  }
+
   if (typing_detector_) {
     // Ignore remote tracks to avoid unnecessary stats computation.
     auto voice_detected =
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h
index a82b231..5411b4f 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor.h
@@ -76,13 +76,21 @@
   // |processed_data| contains the result. Returns false and does not modify the
   // outputs if the internal FIFO has insufficient data. The caller does NOT own
   // the object pointed to by |*processed_data|.
+  // |num_preferred_channels| is the highest number of channels that any sink is
+  // interested in. This can be different from the number of channels in the
+  // output format. A value of -1 means an unknown number. If
+  // use_capture_multi_channel_processing_ is true, the number of channels of
+  // the output of the Audio Processing Module (APM) will be equal to the
+  // highest observed value of num_preferred_channels as long as it does not
+  // exceed the number of channels of the output format.
   // |capture_delay| is an adjustment on the |capture_delay| value provided in
   // the last call to PushCaptureData().
-  // |new_volume| receives the new microphone volume from the AGC.
-  // The new microphone volume range is [0, 255], and the value will be 0 if
-  // the microphone volume should not be adjusted.
+  // |new_volume| receives the new microphone volume from the AGC. The new
+  // microphone volume range is [0, 255], and the value will be 0 if the
+  // microphone volume should not be adjusted.
   // Called on the capture audio thread.
   bool ProcessAndConsumeData(int volume,
+                             int num_preferred_channels,
                              bool key_pressed,
                              media::AudioBus** processed_data,
                              base::TimeDelta* capture_delay,
@@ -152,11 +160,19 @@
   // Called by ProcessAndConsumeData().
   // Returns the new microphone volume in the range of |0, 255].
   // When the volume does not need to be updated, it returns 0.
+  // |num_preferred_channels| is the highest number of channels that any sink is
+  // interested in. This can be different from the number of channels in the
+  // output format. A value of -1 means an unknown number. If
+  // use_capture_multi_channel_processing_ is true, the number of channels of
+  // the output of the Audio Processing Module (APM) will be equal to the
+  // highest observed value of num_preferred_channels as long as it does not
+  // exceed the number of channels of the output format.
   int ProcessData(const float* const* process_ptrs,
                   int process_frames,
                   base::TimeDelta capture_delay,
                   int volume,
                   bool key_pressed,
+                  int num_preferred_channels,
                   float* const* output_ptrs);
 
   // Update AEC stats. Called on the main render thread.
@@ -229,6 +245,14 @@
   // Flag indicating whether capture multi channel processing should be active.
   const bool use_capture_multi_channel_processing_;
 
+  // Observed maximum number of preferred output channels. Used for not
+  // performing audio processing on more channels than the sinks are interested
+  // in. The value is a maximum over time and can increase but never decrease.
+  // If use_capture_multi_channel_processing_ is true, Audio Processing Module
+  // (APM) will output max_num_preferred_output_channels_ channels as long as it
+  // does not exceed the number of channels of the output format.
+  int max_num_preferred_output_channels_ = 1;
+
   DISALLOW_COPY_AND_ASSIGN(MediaStreamAudioProcessor);
 };
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc
index 4d33df8..9d5fbad8 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc
@@ -45,8 +45,6 @@
 
 namespace {
 
-const int kAudioProcessingNumberOfChannel = 1;
-
 // The number of packers used for testing.
 const int kNumberOfPacketsForTest = 100;
 
@@ -76,7 +74,7 @@
 
  protected:
   // Helper method to save duplicated code.
-  void ProcessDataAndVerifyFormat(
+  static void ProcessDataAndVerifyFormat(
       blink::MediaStreamAudioProcessor* audio_processor,
       int expected_output_sample_rate,
       int expected_output_channels,
@@ -133,8 +131,10 @@
       media::AudioBus* processed_data = nullptr;
       base::TimeDelta capture_delay;
       int new_volume = 0;
+      int num_preferred_channels = -1;
       while (audio_processor->ProcessAndConsumeData(
-          255, false, &processed_data, &capture_delay, &new_volume)) {
+          255, num_preferred_channels, false, &processed_data, &capture_delay,
+          &new_volume)) {
         EXPECT_TRUE(processed_data);
         EXPECT_NEAR(input_capture_delay.InMillisecondsF(),
                     capture_delay.InMillisecondsF(),
@@ -148,6 +148,11 @@
       }
 
       data_ptr += params.frames_per_buffer() * params.channels();
+
+      // Test different values of num_preferred_channels.
+      if (++num_preferred_channels > 5) {
+        num_preferred_channels = 0;
+      }
     }
   }
 
@@ -195,7 +200,7 @@
 
   ProcessDataAndVerifyFormat(
       audio_processor.get(), blink::kAudioProcessingSampleRate,
-      kAudioProcessingNumberOfChannel, blink::kAudioProcessingSampleRate / 100);
+      params_.channels(), blink::kAudioProcessingSampleRate / 100);
 
   // Stop |audio_processor| so that it removes itself from
   // |webrtc_audio_device| and clears its pointer to it.
@@ -264,8 +269,7 @@
         blink::kAudioProcessingSampleRate;
 #endif  // BUILDFLAG(IS_CHROMECAST)
     ProcessDataAndVerifyFormat(audio_processor.get(), expected_sample_rate,
-                               kAudioProcessingNumberOfChannel,
-                               expected_sample_rate / 100);
+                               params_.channels(), expected_sample_rate / 100);
   }
 
   // Stop |audio_processor| so that it removes itself from
@@ -310,20 +314,10 @@
 TEST_F(MediaStreamAudioProcessorTest, TestStereoAudio) {
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new rtc::RefCountedObject<WebRtcAudioDeviceImpl>());
-  blink::AudioProcessingProperties properties;
-  // Turn off the audio processing and turn on the stereo channels mirroring.
-  properties.DisableDefaultProperties();
-  properties.goog_audio_mirroring = true;
-  scoped_refptr<MediaStreamAudioProcessor> audio_processor(
-      new rtc::RefCountedObject<MediaStreamAudioProcessor>(
-          properties, webrtc_audio_device.get()));
-  EXPECT_FALSE(audio_processor->has_audio_processing());
+
   const media::AudioParameters source_params(
       media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
       media::CHANNEL_LAYOUT_STEREO, 48000, 480);
-  audio_processor->OnCaptureFormatChanged(source_params);
-  // There's no sense in continuing if this fails.
-  ASSERT_EQ(2, audio_processor->OutputFormat().channels());
 
   // Construct left and right channels, and assign different values to the
   // first data of the left channel and right channel.
@@ -341,28 +335,58 @@
   float* left_channel_ptr = left_channel.get();
   left_channel_ptr[0] = 1.0f;
 
-  // Run the test consecutively to make sure the stereo channels are not
-  // flipped back and forth.
-  static const int kNumberOfPacketsForTest = 100;
-  const base::TimeDelta pushed_capture_delay =
-      base::TimeDelta::FromMilliseconds(42);
-  for (int i = 0; i < kNumberOfPacketsForTest; ++i) {
-    audio_processor->PushCaptureData(*wrapper, pushed_capture_delay);
+  // Test without and with audio processing enabled.
+  for (int use_apm = 0; use_apm <= 1; ++use_apm) {
+    blink::AudioProcessingProperties properties;
+    if (!use_apm) {
+      // Turn off the audio processing.
+      properties.DisableDefaultProperties();
+    }
+    // Turn on the stereo channels mirroring.
+    properties.goog_audio_mirroring = true;
+    scoped_refptr<MediaStreamAudioProcessor> audio_processor(
+        new rtc::RefCountedObject<MediaStreamAudioProcessor>(
+            properties, webrtc_audio_device.get()));
+    EXPECT_EQ(audio_processor->has_audio_processing(), use_apm);
+    audio_processor->OnCaptureFormatChanged(source_params);
+    // There's no sense in continuing if this fails.
+    ASSERT_EQ(2, audio_processor->OutputFormat().channels());
 
+    // Run the test consecutively to make sure the stereo channels are not
+    // flipped back and forth.
+    static const int kNumberOfPacketsForTest = 100;
+    const base::TimeDelta pushed_capture_delay =
+        base::TimeDelta::FromMilliseconds(42);
     media::AudioBus* processed_data = nullptr;
-    base::TimeDelta capture_delay;
-    int new_volume = 0;
-    EXPECT_TRUE(audio_processor->ProcessAndConsumeData(
-        0, false, &processed_data, &capture_delay, &new_volume));
-    EXPECT_TRUE(processed_data);
-    EXPECT_EQ(processed_data->channel(0)[0], 0);
-    EXPECT_NE(processed_data->channel(1)[0], 0);
-    EXPECT_EQ(pushed_capture_delay, capture_delay);
-  }
 
-  // Stop |audio_processor| so that it removes itself from
-  // |webrtc_audio_device| and clears its pointer to it.
-  audio_processor->Stop();
+    for (int num_preferred_channels = 0; num_preferred_channels <= 5;
+         ++num_preferred_channels) {
+      for (int i = 0; i < kNumberOfPacketsForTest; ++i) {
+        audio_processor->PushCaptureData(*wrapper, pushed_capture_delay);
+
+        base::TimeDelta capture_delay;
+        int new_volume = 0;
+        EXPECT_TRUE(audio_processor->ProcessAndConsumeData(
+            0, num_preferred_channels, false, &processed_data, &capture_delay,
+            &new_volume));
+        EXPECT_TRUE(processed_data);
+        EXPECT_EQ(pushed_capture_delay, capture_delay);
+      }
+      if (use_apm && num_preferred_channels <= 1) {
+        // Mono output. Output channels are averaged.
+        EXPECT_NE(processed_data->channel(0)[0], 0);
+        EXPECT_NE(processed_data->channel(1)[0], 0);
+      } else {
+        // Stereo output. Output channels are independent.
+        EXPECT_EQ(processed_data->channel(0)[0], 0);
+        EXPECT_NE(processed_data->channel(1)[0], 0);
+      }
+    }
+
+    // Stop |audio_processor| so that it removes itself from
+    // |webrtc_audio_device| and clears its pointer to it.
+    audio_processor->Stop();
+  }
 }
 
 // Disabled on android clang builds due to crbug.com/470499
@@ -387,7 +411,7 @@
 
   ProcessDataAndVerifyFormat(
       audio_processor.get(), blink::kAudioProcessingSampleRate,
-      kAudioProcessingNumberOfChannel, blink::kAudioProcessingSampleRate / 100);
+      params_.channels(), blink::kAudioProcessingSampleRate / 100);
 
   // Stop |audio_processor| so that it removes itself from
   // |webrtc_audio_device| and clears its pointer to it.
diff --git a/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc b/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
index 6cec225..f63d23f 100644
--- a/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/processed_local_audio_source.cc
@@ -455,9 +455,13 @@
   media::AudioBus* processed_data = nullptr;
   base::TimeDelta processed_data_audio_delay;
   int new_volume = 0;
+
+  // Maximum number of channels used by the sinks.
+  const int num_preferred_channels = NumPreferredChannels();
+
   while (audio_processor_->ProcessAndConsumeData(
-      current_volume, key_pressed, &processed_data, &processed_data_audio_delay,
-      &new_volume)) {
+      current_volume, num_preferred_channels, key_pressed, &processed_data,
+      &processed_data_audio_delay, &new_volume)) {
     DCHECK(processed_data);
 
     level_calculator_.Calculate(*processed_data, force_report_nonzero_energy);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index e412528..d60afd4 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1985,15 +1985,6 @@
 
   ResourceLoader* loader = nullptr;
 
-  if (archive_ && resource->Url().ProtocolIsInHTTPFamily()) {
-    // MHTML documents should not trigger HTTP requests.
-    //
-    // TODO(lukasza): https://crbug.com/1151438: Remove the ad-hoc debugging
-    // below, once the bug is understood.
-    NOTREACHED();
-    base::debug::DumpWithoutCrashing();
-  }
-
   {
     // Forbids JavaScript/revalidation until start()
     // to prevent unintended state transitions.
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h b/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
index 9ff7615..6958ec85 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h
@@ -124,6 +124,18 @@
       consumer->OnData(audio_bus, reference_time);
   }
 
+  // Returns the maximum number of channels preferred by any consumer or -1 if
+  // unknown.
+  int NumPreferredChannels() const {
+    base::AutoLock auto_lock(consumers_lock_);
+    int num_preferred_channels = -1;
+    for (Consumer* consumer : consumers_) {
+      num_preferred_channels =
+          std::max(num_preferred_channels, consumer->NumPreferredChannels());
+    }
+    return num_preferred_channels;
+  }
+
  private:
   // In debug builds, check that all methods that could cause object graph or
   // data flow changes are being called on the main thread.
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
index 047afec..238c73f 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.cc
@@ -261,4 +261,8 @@
   return task_runner_.get();
 }
 
+int MediaStreamAudioSource::NumPreferredChannels() const {
+  return deliverer_.NumPreferredChannels();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
index 47d11ff..245d970 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
@@ -174,6 +174,10 @@
   // Gets the TaskRunner for the main thread, for subclasses that need it.
   base::SingleThreadTaskRunner* GetTaskRunner() const;
 
+  // Maximum number of channels preferred by any connected track or -1 if
+  // unknown.
+  int NumPreferredChannels() const;
+
  private:
   // MediaStreamSource override.
   void DoStopSource() final;
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc b/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc
index 584cc2ce..bd28f31 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.cc
@@ -99,6 +99,10 @@
     sink->OnContentHintChanged(content_hint);
 }
 
+int MediaStreamAudioTrack::NumPreferredChannels() const {
+  return deliverer_.NumPreferredChannels();
+}
+
 void* MediaStreamAudioTrack::GetClassIdentifier() const {
   return nullptr;
 }
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h b/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h
index 4b8d7cae6..df808db 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h
@@ -70,6 +70,10 @@
   void SetContentHint(
       WebMediaStreamTrack::ContentHintType content_hint) override;
 
+  // Returns the maximum number of channels preferred by any sink connected to
+  // this track.
+  int NumPreferredChannels() const;
+
   // Returns a unique class identifier. Some subclasses override and use this
   // method to provide safe down-casting to their type.
   virtual void* GetClassIdentifier() const;
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
index f51e49b..3d4992d 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
@@ -59,7 +59,8 @@
                                              std::move(main_task_runner))),
       fifo_(ConvertToBaseRepeatingCallback(
           CrossThreadBindRepeating(&WebRtcAudioSink::DeliverRebufferedAudio,
-                                   CrossThreadUnretained(this)))) {
+                                   CrossThreadUnretained(this)))),
+      num_preferred_channels_(-1) {
   SendLogMessage(base::StringPrintf("WebRtcAudioSink({label=%s})",
                                     adapter_->label().c_str()));
 }
@@ -152,9 +153,9 @@
       last_estimated_capture_time_ + media::AudioTimestampHelper::FramesToTime(
                                          frame_delay, params_.sample_rate());
 
-  adapter_->DeliverPCMToWebRtcSinks(interleaved_data_.get(),
-                                    params_.sample_rate(), audio_bus.channels(),
-                                    audio_bus.frames(), estimated_capture_time);
+  num_preferred_channels_ = adapter_->DeliverPCMToWebRtcSinks(
+      interleaved_data_.get(), params_.sample_rate(), audio_bus.channels(),
+      audio_bus.frames(), estimated_capture_time);
 }
 
 namespace {
@@ -189,7 +190,7 @@
   }
 }
 
-void WebRtcAudioSink::Adapter::DeliverPCMToWebRtcSinks(
+int WebRtcAudioSink::Adapter::DeliverPCMToWebRtcSinks(
     const int16_t* audio_data,
     int sample_rate,
     size_t number_of_channels,
@@ -203,11 +204,15 @@
   const int64_t capture_timestamp_us = timestamp_aligner_.TranslateTimestamp(
       estimated_capture_time.since_origin().InMicroseconds());
 
+  int num_preferred_channels = -1;
   for (webrtc::AudioTrackSinkInterface* sink : sinks_) {
     sink->OnData(audio_data, sizeof(int16_t) * 8, sample_rate,
                  number_of_channels, number_of_frames,
                  capture_timestamp_us / rtc::kNumMicrosecsPerMillisec);
+    num_preferred_channels =
+        std::max(num_preferred_channels, sink->NumPreferredChannels());
   }
+  return num_preferred_channels;
 }
 
 std::string WebRtcAudioSink::Adapter::kind() const {
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.h b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.h
index d0626b6..b47ca06d 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.h
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <atomic>
 #include <memory>
 #include <string>
 #include <utility>
@@ -99,12 +100,15 @@
     }
 
     // Delivers a 10ms chunk of audio to all WebRTC sinks managed by this
-    // Adapter. This is called on the audio thread.
-    void DeliverPCMToWebRtcSinks(const int16_t* audio_data,
-                                 int sample_rate,
-                                 size_t number_of_channels,
-                                 size_t number_of_frames,
-                                 base::TimeTicks estimated_capture_time);
+    // Adapter and returns the maximum number of channels the sinks are
+    // interested in (number of channels encoded). A return value of -1 means
+    // that the preferred number of channels is unknown. This is called on the
+    // audio thread.
+    int DeliverPCMToWebRtcSinks(const int16_t* audio_data,
+                                int sample_rate,
+                                size_t number_of_channels,
+                                size_t number_of_frames,
+                                base::TimeTicks estimated_capture_time);
 
     std::string label() const { return label_; }
 
@@ -173,6 +177,9 @@
               base::TimeTicks estimated_capture_time) override;
   void OnSetFormat(const media::AudioParameters& params) override;
 
+  // WebMediaStreamAudioSink implementation.
+  int NumPreferredChannels() override { return num_preferred_channels_; }
+
   // Called by AudioPushFifo zero or more times during the call to OnData().
   // Delivers audio data with the required 10ms buffer size to |adapter_|.
   void DeliverRebufferedAudio(const media::AudioBus& audio_bus,
@@ -195,6 +202,10 @@
 
   base::TimeTicks last_estimated_capture_time_;
 
+  // The maximum number of preferred audio channels by any sink or -1 if
+  // unknown.
+  std::atomic<int> num_preferred_channels_;
+
   // In debug builds, check that WebRtcAudioSink's public methods are all being
   // called on the main render thread.
   THREAD_CHECKER(thread_checker_);
diff --git a/third_party/blink/renderer/platform/weborigin/kurl_test.cc b/third_party/blink/renderer/platform/weborigin/kurl_test.cc
index 49a4ac68..799f3da 100644
--- a/third_party/blink/renderer/platform/weborigin/kurl_test.cc
+++ b/third_party/blink/renderer/platform/weborigin/kurl_test.cc
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "url/gurl_abstract_tests.h"
 #include "url/url_util.h"
 
 namespace blink {
@@ -778,20 +779,6 @@
   EXPECT_EQ(String(), invalid_utf8.LastPathComponent());
 }
 
-TEST(KURLTest, IsAboutBlankURL) {
-  EXPECT_TRUE(BlankURL().IsAboutBlankURL());
-
-  EXPECT_TRUE(KURL("about:blank").IsAboutBlankURL());
-  EXPECT_TRUE(KURL("about:blank#ref").IsAboutBlankURL());
-  EXPECT_TRUE(KURL("about:blank?query=123").IsAboutBlankURL());
-}
-
-TEST(KURLTest, IsAboutSrcdocURL) {
-  EXPECT_TRUE(KURL("about:srcdoc").IsAboutSrcdocURL());
-  EXPECT_TRUE(KURL("about:srcdoc#ref").IsAboutSrcdocURL());
-  EXPECT_TRUE(KURL("about:srcdoc?query=123").IsAboutSrcdocURL());
-}
-
 TEST(KURLTest, IsHierarchical) {
   // Note that it's debatable whether "filesystem" URLs are or hierarchical.
   // They're currently registered in the url lib as standard; but the parsed
@@ -1081,3 +1068,26 @@
                          ::testing::ValuesIn(port_test_cases));
 
 }  // namespace blink
+
+// Apparently INSTANTIATE_TYPED_TEST_SUITE_P needs to be used in the same
+// namespace as where the typed test suite was defined.
+namespace url {
+
+class KURLTestTraits final : public UrlTraitsBase<blink::KURL> {
+ public:
+  UrlType CreateUrlFromString(base::StringPiece s) override {
+    return blink::KURL(String::FromUTF8(s));
+  }
+
+  bool IsAboutBlank(const UrlType& url) override {
+    return url.IsAboutBlankURL();
+  }
+
+  bool IsAboutSrcdoc(const UrlType& url) override {
+    return url.IsAboutSrcdocURL();
+  }
+};
+
+INSTANTIATE_TYPED_TEST_SUITE_P(KURL, AbstractUrlTest, KURLTestTraits);
+
+}  // namespace url
diff --git a/third_party/blink/renderer/platform/wtf/hash_iterators.h b/third_party/blink/renderer/platform/wtf/hash_iterators.h
index 6003d02c..b050fd9 100644
--- a/third_party/blink/renderer/platform/wtf/hash_iterators.h
+++ b/third_party/blink/renderer/platform/wtf/hash_iterators.h
@@ -54,10 +54,10 @@
       ValuesIterator;
 
   using iterator_category = std::bidirectional_iterator_tag;
-  using value_type = HashTableType;
+  using value_type = ValueType;
   using difference_type = ptrdiff_t;
-  using pointer = value_type*;
-  using reference = value_type&;
+  using pointer = const ValueType*;
+  using reference = const ValueType&;
 
   HashTableConstIteratorAdapter() = default;
   HashTableConstIteratorAdapter(
@@ -72,13 +72,21 @@
     ++impl_;
     return *this;
   }
-  // postfix ++ intentionally omitted
+  HashTableConstIteratorAdapter operator++(int) {
+    HashTableConstIteratorAdapter copy(*this);
+    ++*this;
+    return copy;
+  }
 
   HashTableConstIteratorAdapter& operator--() {
     --impl_;
     return *this;
   }
-  // postfix -- intentionally omitted
+  HashTableConstIteratorAdapter operator--(int) {
+    HashTableConstIteratorAdapter copy(*this);
+    --*this;
+    return copy;
+  }
 
   KeysIterator Keys() { return KeysIterator(*this); }
   ValuesIterator Values() { return ValuesIterator(*this); }
@@ -101,10 +109,10 @@
       ValuesIterator;
 
   using iterator_category = std::bidirectional_iterator_tag;
-  using value_type = HashTableType;
+  using value_type = ValueType;
   using difference_type = ptrdiff_t;
-  using pointer = value_type*;
-  using reference = value_type&;
+  using pointer = ValueType*;
+  using reference = ValueType&;
 
   HashTableIteratorAdapter() = default;
   HashTableIteratorAdapter(const typename HashTableType::iterator& impl)
@@ -118,13 +126,21 @@
     ++impl_;
     return *this;
   }
-  // postfix ++ intentionally omitted
+  HashTableIteratorAdapter operator++(int) {
+    HashTableIteratorAdapter copy(*this);
+    ++*this;
+    return copy;
+  }
 
   HashTableIteratorAdapter& operator--() {
     --impl_;
     return *this;
   }
-  // postfix -- intentionally omitted
+  HashTableIteratorAdapter operator--(int) {
+    HashTableIteratorAdapter copy(*this);
+    --*this;
+    return copy;
+  }
 
   operator HashTableConstIteratorAdapter<HashTableType, ValueType>() {
     typename HashTableType::const_iterator i = impl_;
@@ -147,6 +163,12 @@
       ConstIterator;
 
  public:
+  using iterator_category = typename ConstIterator::iterator_category;
+  using value_type = KeyType;
+  using difference_type = typename ConstIterator::difference_type;
+  using pointer = const KeyType*;
+  using reference = const KeyType&;
+
   HashTableConstKeysIterator(const ConstIterator& impl) : impl_(impl) {}
 
   const KeyType* Get() const { return &(impl_.Get()->key); }
@@ -157,13 +179,21 @@
     ++impl_;
     return *this;
   }
-  // postfix ++ intentionally omitted
+  HashTableConstKeysIterator operator++(int) {
+    HashTableConstKeysIterator copy(*this);
+    ++*this;
+    return copy;
+  }
 
   HashTableConstKeysIterator& operator--() {
     --impl_;
     return *this;
   }
-  // postfix -- intentionally omitted
+  HashTableConstKeysIterator operator--(int) {
+    HashTableConstKeysIterator copy(*this);
+    --*this;
+    return copy;
+  }
 
   ConstIterator impl_;
 };
@@ -178,6 +208,12 @@
       ConstIterator;
 
  public:
+  using iterator_category = typename ConstIterator::iterator_category;
+  using value_type = MappedType;
+  using difference_type = typename ConstIterator::difference_type;
+  using pointer = const MappedType*;
+  using reference = const MappedType&;
+
   HashTableConstValuesIterator(const ConstIterator& impl) : impl_(impl) {}
 
   const MappedType* Get() const { return &(impl_.Get()->value); }
@@ -188,13 +224,21 @@
     ++impl_;
     return *this;
   }
-  // postfix ++ intentionally omitted
+  HashTableConstValuesIterator operator++(int) {
+    HashTableConstValuesIterator copy(*this);
+    ++*this;
+    return copy;
+  }
 
   HashTableConstValuesIterator& operator--() {
     --impl_;
     return *this;
   }
-  // postfix -- intentionally omitted
+  HashTableConstValuesIterator operator--(int) {
+    HashTableConstValuesIterator copy(*this);
+    --*this;
+    return copy;
+  }
 
   ConstIterator impl_;
 };
@@ -212,6 +256,12 @@
       ConstIterator;
 
  public:
+  using iterator_category = typename Iterator::iterator_category;
+  using value_type = KeyType;
+  using difference_type = typename Iterator::difference_type;
+  using pointer = KeyType*;
+  using reference = KeyType&;
+
   HashTableKeysIterator(const Iterator& impl) : impl_(impl) {}
 
   KeyType* Get() const { return &(impl_.Get()->key); }
@@ -222,13 +272,21 @@
     ++impl_;
     return *this;
   }
-  // postfix ++ intentionally omitted
+  HashTableKeysIterator operator++(int) {
+    HashTableKeysIterator copy(*this);
+    ++*this;
+    return copy;
+  }
 
   HashTableKeysIterator& operator--() {
     --impl_;
     return *this;
   }
-  // postfix -- intentionally omitted
+  HashTableKeysIterator operator--(int) {
+    HashTableKeysIterator copy(*this);
+    --*this;
+    return copy;
+  }
 
   operator HashTableConstKeysIterator<HashTableType, KeyType, MappedType>() {
     ConstIterator i = impl_;
@@ -251,6 +309,12 @@
       ConstIterator;
 
  public:
+  using iterator_category = typename Iterator::iterator_category;
+  using value_type = MappedType;
+  using difference_type = typename Iterator::difference_type;
+  using pointer = MappedType*;
+  using reference = MappedType&;
+
   HashTableValuesIterator(const Iterator& impl) : impl_(impl) {}
 
   MappedType* Get() const { return &(impl_.Get()->value); }
@@ -261,13 +325,21 @@
     ++impl_;
     return *this;
   }
-  // postfix ++ intentionally omitted
+  HashTableValuesIterator operator++(int) {
+    HashTableValuesIterator copy(*this);
+    ++*this;
+    return copy;
+  }
 
   HashTableValuesIterator& operator--() {
     --impl_;
     return *this;
   }
-  // postfix -- intentionally omitted
+  HashTableValuesIterator operator--(int) {
+    HashTableValuesIterator copy(*this);
+    --*this;
+    return copy;
+  }
 
   operator HashTableConstValuesIterator<HashTableType, KeyType, MappedType>() {
     ConstIterator i = impl_;
diff --git a/third_party/blink/renderer/platform/wtf/hash_map_test.cc b/third_party/blink/renderer/platform/wtf/hash_map_test.cc
index 53fb5db..737bb05 100644
--- a/third_party/blink/renderer/platform/wtf/hash_map_test.cc
+++ b/third_party/blink/renderer/platform/wtf/hash_map_test.cc
@@ -25,6 +25,7 @@
 
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
+#include <iterator>
 #include <memory>
 
 #include "base/memory/ptr_util.h"
@@ -640,6 +641,77 @@
 static_assert(!IsTraceable<HashMap<int, int>>::value,
               "HashMap<int, int> must not be traceable.");
 
+static_assert(
+    std::is_convertible<
+        std::iterator_traits<HashMap<int, int>::iterator>::iterator_category,
+        std::bidirectional_iterator_tag>(),
+    "hash map iterators should be bidirectional");
+static_assert(
+    std::is_same<std::iterator_traits<HashMap<int, int>::iterator>::value_type,
+                 KeyValuePair<int, int>>(),
+    "hash map iterators should be over key-value pairs");
+
+static_assert(std::is_convertible<
+                  std::iterator_traits<
+                      HashMap<int, int>::const_iterator>::iterator_category,
+                  std::bidirectional_iterator_tag>(),
+              "hash map const iterators should be bidirectional");
+static_assert(
+    std::is_same<
+        std::iterator_traits<HashMap<int, int>::const_iterator>::value_type,
+        KeyValuePair<int, int>>(),
+    "hash map const iterators should be over key-value pairs");
+
+static_assert(
+    std::is_convertible<
+        std::iterator_traits<
+            HashMap<int, unsigned>::iterator::KeysIterator>::iterator_category,
+        std::bidirectional_iterator_tag>(),
+    "hash map key iterators should be bidirectional");
+static_assert(
+    std::is_same<
+        std::iterator_traits<
+            HashMap<int, unsigned>::iterator::KeysIterator>::value_type,
+        int>(),
+    "hash map key iterators should be over keys");
+
+static_assert(std::is_convertible<
+                  std::iterator_traits<HashMap<int, unsigned>::const_iterator::
+                                           KeysIterator>::iterator_category,
+                  std::bidirectional_iterator_tag>(),
+              "hash map const key iterators should be bidirectional");
+static_assert(
+    std::is_same<
+        std::iterator_traits<
+            HashMap<int, unsigned>::const_iterator::KeysIterator>::value_type,
+        int>(),
+    "hash map const key iterators should be over keys");
+
+static_assert(
+    std::is_convertible<
+        std::iterator_traits<HashMap<int, unsigned>::iterator::ValuesIterator>::
+            iterator_category,
+        std::bidirectional_iterator_tag>(),
+    "hash map value iterators should be bidirectional");
+static_assert(
+    std::is_same<
+        std::iterator_traits<
+            HashMap<int, unsigned>::iterator::ValuesIterator>::value_type,
+        unsigned>(),
+    "hash map value iterators should be over values");
+
+static_assert(std::is_convertible<
+                  std::iterator_traits<HashMap<int, unsigned>::const_iterator::
+                                           ValuesIterator>::iterator_category,
+                  std::bidirectional_iterator_tag>(),
+              "hash map const value iterators should be bidirectional");
+static_assert(
+    std::is_same<
+        std::iterator_traits<
+            HashMap<int, unsigned>::const_iterator::ValuesIterator>::value_type,
+        unsigned>(),
+    "hash map const value iterators should be over values");
+
 }  // anonymous namespace
 
 }  // namespace WTF
diff --git a/third_party/blink/tools/blinkpy/common/system/executive.py b/third_party/blink/tools/blinkpy/common/system/executive.py
index 2c31f70..e11599d8 100644
--- a/third_party/blink/tools/blinkpy/common/system/executive.py
+++ b/third_party/blink/tools/blinkpy/common/system/executive.py
@@ -374,8 +374,13 @@
             env=env,
             close_fds=self._should_close_fds())
 
+        def on_command_timeout():
+            _log.error('Error: Command timed out after %s seconds',
+                       timeout_seconds)
+            process.kill()
+
         if timeout_seconds:
-            timer = threading.Timer(timeout_seconds, process.kill)
+            timer = threading.Timer(timeout_seconds, on_command_timeout)
             timer.start()
 
         output = process.communicate(string_to_communicate)[0]
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer.py b/third_party/blink/tools/blinkpy/w3c/test_importer.py
index 9e3641c..047fb81a 100644
--- a/third_party/blink/tools/blinkpy/w3c/test_importer.py
+++ b/third_party/blink/tools/blinkpy/w3c/test_importer.py
@@ -404,8 +404,7 @@
         stages the generated MANIFEST.json in the git index, ready to commit.
         """
         _log.info('Generating MANIFEST.json')
-        WPTManifest.generate_manifest(self.host.port_factory.get(),
-                                      self.dest_path)
+        WPTManifest.generate_manifest(self.host, self.dest_path)
         manifest_path = self.fs.join(self.dest_path, 'MANIFEST.json')
         assert self.fs.exists(manifest_path)
         manifest_base_path = self.fs.normpath(
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py b/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
index 74c0b621..6824e7ad 100644
--- a/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
@@ -25,9 +25,9 @@
 
 MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS
 MANIFEST_INSTALL_CMD = [
-    'python3',
+    'python',
     '/mock-checkout/third_party/blink/tools/blinkpy/third_party/wpt/wpt/wpt',
-    'manifest', '--no-download', '--tests-root',
+    '--py2', 'manifest', '-v', '--no-download', '--tests-root',
     MOCK_WEB_TESTS + 'external/wpt'
 ]
 
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py b/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
index 35d4541..247b408 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
@@ -317,7 +317,7 @@
                 _log.error('Manifest base not found at "%s".',
                            base_manifest_path)
 
-        WPTManifest.generate_manifest(port, wpt_path)
+        WPTManifest.generate_manifest(port.host, wpt_path)
 
         if fs.isfile(manifest_path):
             _log.debug('Manifest generation completed.')
@@ -328,19 +328,19 @@
             fs.write_text_file(manifest_path, '{}')
 
     @staticmethod
-    def generate_manifest(port, dest_path):
+    def generate_manifest(host, dest_path):
         """Generates MANIFEST.json on the specified directory."""
-        wpt_exec_path = PathFinder(port.host.filesystem).path_from_blink_tools(
+        wpt_exec_path = PathFinder(host.filesystem).path_from_blink_tools(
             'blinkpy', 'third_party', 'wpt', 'wpt', 'wpt')
         cmd = [
-            port.python3_command(), wpt_exec_path, 'manifest', '--no-download',
-            '--tests-root', dest_path
+            'python', wpt_exec_path, '--py2', 'manifest', '-v',
+            '--no-download', '--tests-root', dest_path
         ]
 
         # ScriptError will be raised if the command fails.
-        output = port.host.executive.run_command(
+        output = host.executive.run_command(
             cmd,
-            timeout_seconds=300,
+            timeout_seconds=600,
             # This will also include stderr in the exception message.
             return_stderr=True)
         if output:
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
index b48d98a..84da208 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
@@ -24,9 +24,11 @@
                          {manifest_path: '{"manifest": "base"}'})
 
         self.assertEqual(host.executive.calls, [[
-            'python3',
+            'python',
             '/mock-checkout/third_party/blink/tools/blinkpy/third_party/wpt/wpt/wpt',
+            '--py2',
             'manifest',
+            '-v',
             '--no-download',
             '--tests-root',
             WEB_TEST_DIR + '/external/wpt',
@@ -47,9 +49,11 @@
                          {manifest_path: '{"manifest": "base"}'})
 
         self.assertEqual(host.executive.calls, [[
-            'python3',
+            'python',
             '/mock-checkout/third_party/blink/tools/blinkpy/third_party/wpt/wpt/wpt',
+            '--py2',
             'manifest',
+            '-v',
             '--no-download',
             '--tests-root',
             WEB_TEST_DIR + '/external/wpt',
@@ -68,9 +72,11 @@
         port = TestPort(host)
         WPTManifest.ensure_manifest(port, 'wpt_internal')
         self.assertEqual(host.executive.calls, [[
-            'python3',
+            'python',
             '/mock-checkout/third_party/blink/tools/blinkpy/third_party/wpt/wpt/wpt',
+            '--py2',
             'manifest',
+            '-v',
             '--no-download',
             '--tests-root',
             WEB_TEST_DIR + '/wpt_internal',
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 9791fac..a94df23 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2074,9 +2074,9 @@
 # Memory measurement tests are run as virtual tests.
 external/wpt/measure-memory/* [ Skip ]
 virtual/force-eager/external/wpt/measure-memory/* [ Pass ]
-crbug.com/1150938 virtual/force-eager/external/wpt/measure-memory/detached.tentative.https.window.html [ Skip ]
-crbug.com/1150938 virtual/force-eager/external/wpt/measure-memory/window-open.mix.tentative.https.window.html [ Skip ]
-crbug.com/1085129 virtual/force-eager/external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.html [ Skip ]
+crbug.com/1150938 virtual/force-eager/external/wpt/measure-memory/detached.https.window.html [ Skip ]
+crbug.com/1150938 virtual/force-eager/external/wpt/measure-memory/window-open.mix.https.window.html [ Skip ]
+crbug.com/1085129 virtual/force-eager/external/wpt/measure-memory/main-frame-and-worker.https.window.html [ Skip ]
 
 # Legacy SameSite cookie tests do not apply when non-legacy behavior is in effect.
 crbug.com/961439 external/wpt/cookies/samesite/fetch.https.html?legacy-samesite [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 14e5e01..a318fd5 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -536,6 +536,9 @@
 crbug.com/417223 external/wpt/css/css-position/position-relative-table-tr-top.html [ Failure ]
 
 #### external/wpt/css/css-sizing
+crbug.com/1164135 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-025.html [ Failure ]
+crbug.com/1164135 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-026.html [ Failure ]
+crbug.com/1164474 external/wpt/css/css-sizing/aspect-ratio/table-element-001.html [ Failure ]
 crbug.com/1158406 external/wpt/css/css-sizing/intrinsic-percent-replaced-009.html [ Failure ]
 
 crbug.com/1008951 external/wpt/css/css-text-decor/text-decoration-subelements-002.html [ Failure ]
@@ -2295,8 +2298,6 @@
 # css-pseudo-4 opacity not applied to ::first-line
 crbug.com/1085772 external/wpt/css/css-pseudo/first-line-opacity-001.html [ Failure ]
 
-crbug.com/1165324 http/tests/devtools/console/console-preserve-log-x-process-navigation.js [ Pass Failure ]
-
 # motion-1 issues
 crbug.com/641245 external/wpt/css/motion/offset-path-ray-002.html [ Failure ]
 crbug.com/641245 external/wpt/css/motion/offset-path-ray-003.html [ Failure ]
@@ -2472,9 +2473,6 @@
 # ====== New tests from wpt-importer added here ======
 crbug.com/626703 [ Mac10.13 ] external/wpt/x-frame-options/multiple.html [ Timeout ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/FileAPI/idlharness.worker.html [ Timeout ]
-crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/table-element-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-025.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-026.html [ Failure ]
 crbug.com/626703 external/wpt/html/interaction/focus/document-level-focus-apis/document-has-system-focus.html [ Timeout ]
 crbug.com/626703 [ Mac11.0 ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-set-keyframes.https.html [ Failure ]
 crbug.com/626703 external/wpt/websockets/cookies/004.html [ Timeout ]
@@ -5706,7 +5704,6 @@
 crbug.com/1159445 [ Mac ] paint/invalidation/repaint-overlay/layers-overlay.html [ Failure ]
 
 crbug.com/1140329 http/tests/devtools/network/network-filter-service-worker.js [ Pass Timeout Failure ]
-crbug.com/1140329 virtual/threaded/external/wpt/web-animations/timing-model/animations/updating-the-finished-state.html [ Pass Failure Timeout ]
 
 #Sheriff 2020-10-21
 crbug.com/1141206 scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ]
@@ -5770,25 +5767,6 @@
 crbug.com/1032451 virtual/threaded-no-composited-antialiasing/animations/stability/animation-iteration-event-destroy-renderer.html [ Pass Timeout ]
 crbug.com/931646 [ Mac ] http/tests/preload/meta-viewport-link-headers-imagesrcset.html [ Failure Pass ]
 
-
-#Imperceptible image diffs after Skia change.
-skbug.com/11019 compositing/reflections/nested-reflection-animated.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-background-image-cover.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-background-image-cross-fade.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-background-image-repeat.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-background-image-space.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-border-image.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-image-canvas-pattern.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-image-canvas.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/color-profile-object.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter.html [ Pass Failure ]
-skbug.com/11019 virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image.html [ Pass Failure ]
-
 # Win7 suggestion picker appearance tests have a scrollbar flakiness issue
 crbug.com/1045510 [ Win7 ] fast/forms/suggestion-picker/date-suggestion-picker-appearance-rtl.html [ Pass Failure ]
 crbug.com/1045510 [ Win7 ] fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/android/ChromiumWPTExpectations b/third_party/blink/web_tests/android/ChromiumWPTExpectations
index daef556b..df401114 100644
--- a/third_party/blink/web_tests/android/ChromiumWPTExpectations
+++ b/third_party/blink/web_tests/android/ChromiumWPTExpectations
@@ -3145,19 +3145,19 @@
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/tabindex-001.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/tabindex-002.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/detached.tentative.https.window.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.cross-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.cross-site.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.same-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/main-frame.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/redirect.client.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/redirect.server.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.cross-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.cross-site.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.mix.tentative.https.window.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.same-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/randomized-breakdown.tentative.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/detached.https.window.html [ Failure Timeout ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.cross-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.cross-site.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.same-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/main-frame-and-worker.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/main-frame.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/redirect.client.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/redirect.server.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.cross-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.cross-site.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.mix.https.window.html [ Failure Timeout ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.same-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/randomized-breakdown.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/decodingInfo.any.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/decodingInfo.any.worker.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/encodingInfo.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/android/WeblayerWPTExpectations b/third_party/blink/web_tests/android/WeblayerWPTExpectations
index 95a18906..71a3845 100644
--- a/third_party/blink/web_tests/android/WeblayerWPTExpectations
+++ b/third_party/blink/web_tests/android/WeblayerWPTExpectations
@@ -3125,19 +3125,19 @@
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/tabindex-001.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/tabindex-002.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/measure-memory/detached.tentative.https.window.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.cross-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.cross-site.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.same-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/main-frame.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/redirect.client.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/redirect.server.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.cross-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.cross-site.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.mix.tentative.https.window.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.same-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/randomized-breakdown.tentative.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/detached.https.window.html [ Failure Timeout ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.cross-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.cross-site.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.same-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/main-frame-and-worker.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/main-frame.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/redirect.client.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/redirect.server.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.cross-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.cross-site.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.mix.https.window.html [ Failure Timeout ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.same-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/randomized-breakdown.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/decodingInfo.any.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/decodingInfo.any.worker.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/encodingInfo.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WebviewWPTExpectations b/third_party/blink/web_tests/android/WebviewWPTExpectations
index 47bb5ccb..0af47e69 100644
--- a/third_party/blink/web_tests/android/WebviewWPTExpectations
+++ b/third_party/blink/web_tests/android/WebviewWPTExpectations
@@ -3372,19 +3372,19 @@
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/math-global-event-handlers.tentative.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/tabindex-001.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/mathml/relations/html5-tree/tabindex-002.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/detached.tentative.https.window.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.cross-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.cross-site.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/iframe.same-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/main-frame.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/redirect.client.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/redirect.server.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.cross-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.cross-site.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.mix.tentative.https.window.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/measure-memory/window-open.same-origin.tentative.https.window.html [ Failure ]
-crbug.com/1050754 external/wpt/measure-memory/randomized-breakdown.tentative.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/detached.https.window.html [ Failure Timeout ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.cross-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.cross-site.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/iframe.same-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/main-frame-and-worker.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/main-frame.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/redirect.client.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/redirect.server.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.cross-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.cross-site.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.mix.https.window.html [ Failure Timeout ]
+crbug.com/1050754 external/wpt/measure-memory/window-open.same-origin.https.window.html [ Failure ]
+crbug.com/1050754 external/wpt/measure-memory/randomized-breakdown.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/decodingInfo.any.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/decodingInfo.any.worker.html [ Failure ]
 crbug.com/1050754 external/wpt/media-capabilities/encodingInfo.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index d6f23f6..e55bbfe 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
@@ -10260,7 +10260,7 @@
      ]
     ],
     "usbDevice_transferIn-manual.https.html": [
-     "bd3df7d54ea63b45920d31d5719782ca1f066911",
+     "c0fad37e2090c1dfc06f48c978bb9fdf424f4fa9",
      [
       null,
       {}
@@ -105326,6 +105326,23 @@
         {}
        ]
       ],
+      "hyphens-auto-last-word-001.html": [
+       "273f060d871eb4787e27afc704bdab609179a1f1",
+       [
+        null,
+        [
+         [
+          "/css/css-text/hyphens/reference/hyphens-auto-last-word-001-ref.html",
+          "=="
+         ],
+         [
+          "/css/css-text/hyphens/reference/hyphens-auto-last-word-001-ref2.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "hyphens-manual-010.html": [
        "8ceaceb1f3f1486b1e9cee141f821d634f946527",
        [
@@ -105541,6 +105558,19 @@
         {}
        ]
       ],
+      "hyphens-punctuation-001.html": [
+       "feea83635c736c13ff7014bab4d16f7a3dd9bb61",
+       [
+        null,
+        [
+         [
+          "/css/css-text/hyphens/reference/hyphens-punctuation-001-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "hyphens-shaping-001.html": [
        "0cd2243bdac0e89add0223c03ba2328cb239c980",
        [
@@ -116268,6 +116298,123 @@
         {}
        ]
       ],
+      "trailing-ideographic-space-017.html": [
+       "742e389950f1957a79300bbaa979dddb108973ce",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "trailing-ideographic-space-018.html": [
+       "16bb8767512a4c9b555decda04d5d3316c911231",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "trailing-ideographic-space-019.html": [
+       "0707000512030c2e94fae2a753c75288caeb6e4a",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "trailing-ideographic-space-020.html": [
+       "97ae007898b8e62914720b167848dfd50894b6fb",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "trailing-ideographic-space-021.html": [
+       "b75327a64ba957ba9a4867c7c796a682c2490e5c",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "trailing-ideographic-space-022.html": [
+       "71720c2b2d7f70e54a0303e7f1a0cdeaece3e9ea",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "trailing-ideographic-space-023.html": [
+       "ea95ab1e0f2a28f7ed6c438cedee918682d8b07a",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "trailing-ideographic-space-024.html": [
+       "2a65400c60015797f16946092ca9663e76b6d2ac",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "trailing-ideographic-space-025.html": [
+       "5123e10524f7297a7e9a7fb890a52d458737f55d",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "trailing-ideographic-space-break-spaces-001.html": [
        "2ab5edffc0c6bee14382cb35c5960a36c62cee46",
        [
@@ -202282,6 +202429,14 @@
         "59f5247e50fd9f42187193af7eafa9d385a14229",
         []
        ],
+       "hyphens-auto-last-word-001-ref.html": [
+        "7fe23fe75d633750026ef0ab4cf60760ab92d96a",
+        []
+       ],
+       "hyphens-auto-last-word-001-ref2.html": [
+        "9c9f41312e8da239ca02b435e3fa0ab7a14e669a",
+        []
+       ],
        "hyphens-manual-010-ref.html": [
         "f79ce17a4c71bfac19b543b70bb8e95510bad321",
         []
@@ -202330,6 +202485,10 @@
         "db002ce45d84a89ba9692e8e6d3c97a5227fc64f",
         []
        ],
+       "hyphens-punctuation-001-ref.html": [
+        "75e2363789047924c68527d74abedcaa206e3bb5",
+        []
+       ],
        "hyphens-shaping-001-ref.html": [
         "9eb1d7fd686e0f9bc1c82baf2235f8f1ef8cbb81",
         []
@@ -218900,6 +219059,16 @@
        []
       ]
      },
+     "body": {
+      "mime-type.any-expected.txt": [
+       "3de828baab31cabf35d04c2ab253965cf0088f25",
+       []
+      ],
+      "mime-type.any.worker-expected.txt": [
+       "3de828baab31cabf35d04c2ab253965cf0088f25",
+       []
+      ]
+     },
      "cors": {
       "cors-preflight-redirect.any-expected.txt": [
        "1130f249e167d39118bfc9eb330b2690b2fa7cce",
@@ -238183,39 +238352,39 @@
      "953611f93037cfebe0459d5f67599b727539ae40",
      []
     ],
-    "detached.tentative.https.window.js.headers": [
+    "detached.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "iframe.cross-origin.tentative.https.window.js.headers": [
+    "iframe.cross-origin.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "iframe.cross-site.tentative.https.window.js.headers": [
+    "iframe.cross-site.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "iframe.same-origin.tentative.https.window.js.headers": [
+    "iframe.same-origin.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "main-frame-and-worker.tentative.https.window.js.headers": [
+    "main-frame-and-worker.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "main-frame.tentative.https.window.js.headers": [
+    "main-frame.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "randomized-breakdown.tentative.https.window.js.headers": [
+    "randomized-breakdown.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "redirect.client.tentative.https.window.js.headers": [
+    "redirect.client.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "redirect.server.tentative.https.window.js.headers": [
+    "redirect.server.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
@@ -238285,19 +238454,19 @@
       []
      ]
     },
-    "window-open.cross-origin.tentative.https.window.js.headers": [
+    "window-open.cross-origin.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "window-open.cross-site.tentative.https.window.js.headers": [
+    "window-open.cross-site.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "window-open.mix.tentative.https.window.js.headers": [
+    "window-open.mix.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ],
-    "window-open.same-origin.tentative.https.window.js.headers": [
+    "window-open.same-origin.https.window.js.headers": [
      "4fff9d9fba4c81f953826ffea010a75be626b95d",
      []
     ]
@@ -245066,7 +245235,7 @@
        []
       ],
       "cache-match.js": [
-       "8bf7fda30967fbb4ed25325d49e0cd99fc16df55",
+       "60c0dd0a02f20e1d4fa7d30a4d0a5968507aca03",
        []
       ],
       "cache-matchAll.js": [
@@ -245099,6 +245268,10 @@
        "a83c246e6e7829a28be331d3d7188b908ec402a8",
        []
       ],
+      "cache-match.https-expected.txt": [
+       "2173cd807f2c9c868b8c661e3f1d92988475df0b",
+       []
+      ],
       "cache-matchAll.https-expected.txt": [
        "83bb89f3ee9513307805617ffbc90144913f3ac4",
        []
@@ -245113,6 +245286,10 @@
        "88c51077ad20e44a3c3fac6b24ae32eb6e8d2a21",
        []
       ],
+      "cache-match.https-expected.txt": [
+       "502a117fa91e1c39c2518e449b3b6542ad603783",
+       []
+      ],
       "cache-matchAll.https-expected.txt": [
        "69fcf49eb19a1b24c5c84d67b33585e77b40182a",
        []
@@ -245131,6 +245308,10 @@
        "88c51077ad20e44a3c3fac6b24ae32eb6e8d2a21",
        []
       ],
+      "cache-match.https-expected.txt": [
+       "502a117fa91e1c39c2518e449b3b6542ad603783",
+       []
+      ],
       "cache-matchAll.https-expected.txt": [
        "69fcf49eb19a1b24c5c84d67b33585e77b40182a",
        []
@@ -261169,7 +261350,7 @@
       []
      ],
      "manual.js": [
-      "869ac450acf19a029eb924a6b290bcabc1acff2d",
+      "e8dc08a8bde4343dd37c8f9e1cf03a16a5fb3445",
       []
      ],
      "open-in-iframe.html": [
@@ -336226,6 +336407,19 @@
        ]
       ]
      },
+     "body": {
+      "mime-type.any.js": [
+       "a0f90a0abdfc3e672997607611438ff0049ecf2c",
+       [
+        "fetch/api/body/mime-type.any.html",
+        {}
+       ],
+       [
+        "fetch/api/body/mime-type.any.worker.html",
+        {}
+       ]
+      ]
+     },
      "cors": {
       "cors-basic.any.js": [
        "23f5f91c87d49f648dbbe575cc901562a5277c8b",
@@ -388275,10 +388469,10 @@
     }
    },
    "measure-memory": {
-    "detached.tentative.https.window.js": [
+    "detached.https.window.js": [
      "179e5e727adfd9b12e82b84b0c39a7c682a6689d",
      [
-      "measure-memory/detached.tentative.https.window.html",
+      "measure-memory/detached.https.window.html",
       {
        "script_metadata": [
         [
@@ -388298,67 +388492,10 @@
       }
      ]
     ],
-    "idlharness.tentative.any.js": [
+    "idlharness.window.js": [
      "3e7589aeb95e2d06aa7bfd799a3e5afb342c0fce",
      [
-      "measure-memory/idlharness.tentative.any.html",
-      {
-       "script_metadata": [
-        [
-         "global",
-         "window,worker"
-        ],
-        [
-         "script",
-         "/resources/WebIDLParser.js"
-        ],
-        [
-         "script",
-         "/resources/idlharness.js"
-        ]
-       ]
-      }
-     ],
-     [
-      "measure-memory/idlharness.tentative.any.serviceworker.html",
-      {
-       "script_metadata": [
-        [
-         "global",
-         "window,worker"
-        ],
-        [
-         "script",
-         "/resources/WebIDLParser.js"
-        ],
-        [
-         "script",
-         "/resources/idlharness.js"
-        ]
-       ]
-      }
-     ],
-     [
-      "measure-memory/idlharness.tentative.any.sharedworker.html",
-      {
-       "script_metadata": [
-        [
-         "global",
-         "window,worker"
-        ],
-        [
-         "script",
-         "/resources/WebIDLParser.js"
-        ],
-        [
-         "script",
-         "/resources/idlharness.js"
-        ]
-       ]
-      }
-     ],
-     [
-      "measure-memory/idlharness.tentative.any.worker.html",
+      "measure-memory/idlharness.window.html",
       {
        "script_metadata": [
         [
@@ -388377,10 +388514,10 @@
       }
      ]
     ],
-    "iframe.cross-origin.tentative.https.window.js": [
+    "iframe.cross-origin.https.window.js": [
      "ac0641cc2621df534faedfe50d22dac5bde3cb15",
      [
-      "measure-memory/iframe.cross-origin.tentative.https.window.html",
+      "measure-memory/iframe.cross-origin.https.window.html",
       {
        "script_metadata": [
         [
@@ -388400,10 +388537,10 @@
       }
      ]
     ],
-    "iframe.cross-site.tentative.https.window.js": [
+    "iframe.cross-site.https.window.js": [
      "1b4dfc70b7e10ef4a304513b8b7446ea27df41c6",
      [
-      "measure-memory/iframe.cross-site.tentative.https.window.html",
+      "measure-memory/iframe.cross-site.https.window.html",
       {
        "script_metadata": [
         [
@@ -388423,10 +388560,10 @@
       }
      ]
     ],
-    "iframe.same-origin.tentative.https.window.js": [
+    "iframe.same-origin.https.window.js": [
      "1d546b27f302ace49618d448cfcb13f668631c08",
      [
-      "measure-memory/iframe.same-origin.tentative.https.window.html",
+      "measure-memory/iframe.same-origin.https.window.html",
       {
        "script_metadata": [
         [
@@ -388446,10 +388583,10 @@
       }
      ]
     ],
-    "main-frame-and-worker.tentative.https.window.js": [
+    "main-frame-and-worker.https.window.js": [
      "f0b8abf1bc6dca66f57a0bd4f2152f6c479de6f2",
      [
-      "measure-memory/main-frame-and-worker.tentative.https.window.html",
+      "measure-memory/main-frame-and-worker.https.window.html",
       {
        "script_metadata": [
         [
@@ -388469,10 +388606,10 @@
       }
      ]
     ],
-    "main-frame.tentative.https.window.js": [
+    "main-frame.https.window.js": [
      "fd58e9314b0980154a9e828e0212dee2f20309d5",
      [
-      "measure-memory/main-frame.tentative.https.window.html",
+      "measure-memory/main-frame.https.window.html",
       {
        "script_metadata": [
         [
@@ -388492,10 +388629,10 @@
       }
      ]
     ],
-    "randomized-breakdown.tentative.https.window.js": [
+    "randomized-breakdown.https.window.js": [
      "e3a65c1ba2a6a90c142b9c2da3368fc949c874b7",
      [
-      "measure-memory/randomized-breakdown.tentative.https.window.html",
+      "measure-memory/randomized-breakdown.https.window.html",
       {
        "script_metadata": [
         [
@@ -388515,10 +388652,10 @@
       }
      ]
     ],
-    "redirect.client.tentative.https.window.js": [
+    "redirect.client.https.window.js": [
      "36d9a9d44cd1734572c2b3b930cec7ff0b3eeee2",
      [
-      "measure-memory/redirect.client.tentative.https.window.html",
+      "measure-memory/redirect.client.https.window.html",
       {
        "script_metadata": [
         [
@@ -388538,10 +388675,10 @@
       }
      ]
     ],
-    "redirect.server.tentative.https.window.js": [
+    "redirect.server.https.window.js": [
      "6506730b34cbe681a72a65b290c3c2e5b012f5e5",
      [
-      "measure-memory/redirect.server.tentative.https.window.html",
+      "measure-memory/redirect.server.https.window.html",
       {
        "script_metadata": [
         [
@@ -388561,10 +388698,10 @@
       }
      ]
     ],
-    "window-open.cross-origin.tentative.https.window.js": [
+    "window-open.cross-origin.https.window.js": [
      "2e6561ad44bbd8345102e627dbe079ea7f98605e",
      [
-      "measure-memory/window-open.cross-origin.tentative.https.window.html",
+      "measure-memory/window-open.cross-origin.https.window.html",
       {
        "script_metadata": [
         [
@@ -388584,10 +388721,10 @@
       }
      ]
     ],
-    "window-open.cross-site.tentative.https.window.js": [
+    "window-open.cross-site.https.window.js": [
      "f70ad9df32b92640160503550afcbb9a4168943e",
      [
-      "measure-memory/window-open.cross-site.tentative.https.window.html",
+      "measure-memory/window-open.cross-site.https.window.html",
       {
        "script_metadata": [
         [
@@ -388607,10 +388744,10 @@
       }
      ]
     ],
-    "window-open.mix.tentative.https.window.js": [
+    "window-open.mix.https.window.js": [
      "6a913a88a4876ae096b989658384c8848b14f227",
      [
-      "measure-memory/window-open.mix.tentative.https.window.html",
+      "measure-memory/window-open.mix.https.window.html",
       {
        "script_metadata": [
         [
@@ -388630,10 +388767,10 @@
       }
      ]
     ],
-    "window-open.same-origin.tentative.https.window.js": [
+    "window-open.same-origin.https.window.js": [
      "5223a97bc7d2fc4ca55fbd5e06d979abe78d2ca1",
      [
-      "measure-memory/window-open.same-origin.tentative.https.window.html",
+      "measure-memory/window-open.same-origin.https.window.html",
       {
        "script_metadata": [
         [
@@ -412866,7 +413003,7 @@
      ]
     ],
     "current-time.html": [
-     "cbe2d8d6005b0a0e361f858cdfc6b894dbce9011",
+     "fe8c64a6addc911147d480d73060756859e04f8b",
      [
       null,
       {}
@@ -412918,6 +413055,13 @@
       }
      ]
     ],
+    "multiple-scroll-offsets.tentative.html": [
+     "026b2e7673c8b863dc27072a9a4b06664f46d051",
+     [
+      null,
+      {}
+     ]
+    ],
     "pause-animation.html": [
      "9bddfedd436675ff940b935ce46aab250b2cdd11",
      [
@@ -433456,6 +433600,69 @@
        }
       ]
      ],
+     "modified-contenttype.any.js": [
+      "354930517c73ea54162a655c2c12e93b40cc1a73",
+      [
+       "wasm/webapi/modified-contenttype.any.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/wasm/jsapi/wasm-module-builder.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "wasm/webapi/modified-contenttype.any.serviceworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/wasm/jsapi/wasm-module-builder.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "wasm/webapi/modified-contenttype.any.sharedworker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/wasm/jsapi/wasm-module-builder.js"
+         ]
+        ]
+       }
+      ],
+      [
+       "wasm/webapi/modified-contenttype.any.worker.html",
+       {
+        "script_metadata": [
+         [
+          "global",
+          "window,worker"
+         ],
+         [
+          "script",
+          "/wasm/jsapi/wasm-module-builder.js"
+         ]
+        ]
+       }
+      ]
+     ],
      "origin.sub.any.js": [
       "bf7901eeddee7c28413031198c4f138b7a23d6ea",
       [
@@ -438745,6 +438952,15 @@
       }
      ]
     ],
+    "RTCDataChannel-iceRestart.html": [
+     "648c11b66a4641a44374763a38bed8cebea2267a",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
     "RTCDataChannel-id.html": [
      "10dc5eacb9ccf2a878d29e8b13eb082271731e65",
      [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/intrinsic-size-009.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/intrinsic-size-009.html
new file mode 100644
index 0000000..139c4de
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/intrinsic-size-009.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>CSS aspect-ratio: max-content size contribution with replaced element</title>
+<link rel="author" title="Google LLC" href="https://www.google.com/">
+<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht" />
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div style="display: flex;">
+  <div>
+    <img style="width: 100%; height: 100%; vertical-align: bottom;" width="100" height="100" src="support/100x100-green.png">
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/support/100x100-green.png b/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/support/100x100-green.png
new file mode 100644
index 0000000..25b76c3c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/support/100x100-green.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any-expected.txt
new file mode 100644
index 0000000..3de828b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL Request: overriding explicit Content-Type assert_equals: expected "test/test" but got "text/plain"
+FAIL Response: overriding explicit Content-Type assert_equals: expected "test/test" but got "text/plain"
+FAIL Request: removing implicit Content-Type assert_equals: expected "" but got "application/x-www-form-urlencoded;charset=utf-8"
+FAIL Response: removing implicit Content-Type assert_equals: expected "" but got "application/x-www-form-urlencoded;charset=utf-8"
+FAIL Request: setting missing Content-Type assert_equals: expected "test/test" but got ""
+FAIL Response: setting missing Content-Type assert_equals: expected "test/test" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any.js
new file mode 100644
index 0000000..a0f90a0a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any.js
@@ -0,0 +1,40 @@
+[
+ () => new Request("about:blank", { headers: { "Content-Type": "text/plain" } }),
+ () => new Response("", { headers: { "Content-Type": "text/plain" } })
+].forEach(bodyContainerCreator => {
+  const bodyContainer = bodyContainerCreator();
+  promise_test(async t => {
+    assert_equals(bodyContainer.headers.get("Content-Type"), "text/plain");
+    const newMIMEType = "test/test";
+    bodyContainer.headers.set("Content-Type", newMIMEType);
+    const blob = await bodyContainer.blob();
+    assert_equals(blob.type, newMIMEType);
+  }, `${bodyContainer.constructor.name}: overriding explicit Content-Type`);
+});
+
+[
+  () => new Request("about:blank", { body: new URLSearchParams(), method: "POST" }),
+  () => new Response(new URLSearchParams()),
+].forEach(bodyContainerCreator => {
+  const bodyContainer = bodyContainerCreator();
+  promise_test(async t => {
+    assert_equals(bodyContainer.headers.get("Content-Type"), "application/x-www-form-urlencoded;charset=UTF-8");
+    bodyContainer.headers.delete("Content-Type");
+    const blob = await bodyContainer.blob();
+    assert_equals(blob.type, "");
+  }, `${bodyContainer.constructor.name}: removing implicit Content-Type`);
+});
+
+[
+  () => new Request("about:blank", { body: new ArrayBuffer(), method: "POST" }),
+  () => new Response(new ArrayBuffer()),
+].forEach(bodyContainerCreator => {
+  const bodyContainer = bodyContainerCreator();
+  promise_test(async t => {
+    assert_equals(bodyContainer.headers.get("Content-Type"), null);
+    const newMIMEType = "test/test";
+    bodyContainer.headers.set("Content-Type", newMIMEType);
+    const blob = await bodyContainer.blob();
+    assert_equals(blob.type, newMIMEType);
+  }, `${bodyContainer.constructor.name}: setting missing Content-Type`);
+});
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any.worker-expected.txt
new file mode 100644
index 0000000..3de828b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/body/mime-type.any.worker-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL Request: overriding explicit Content-Type assert_equals: expected "test/test" but got "text/plain"
+FAIL Response: overriding explicit Content-Type assert_equals: expected "test/test" but got "text/plain"
+FAIL Request: removing implicit Content-Type assert_equals: expected "" but got "application/x-www-form-urlencoded;charset=utf-8"
+FAIL Response: removing implicit Content-Type assert_equals: expected "" but got "application/x-www-form-urlencoded;charset=utf-8"
+FAIL Request: setting missing Content-Type assert_equals: expected "test/test" but got ""
+FAIL Response: setting missing Content-Type assert_equals: expected "test/test" but got ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/README.md b/third_party/blink/web_tests/external/wpt/measure-memory/README.md
index 953611f..d80c0e0 100644
--- a/third_party/blink/web_tests/external/wpt/measure-memory/README.md
+++ b/third_party/blink/web_tests/external/wpt/measure-memory/README.md
@@ -1,8 +1,6 @@
-# Tentative tests for performance.measureMemory API
+# Tests for performance.measureMemory API
 
-Tests in this directory are for the proposed performance.measureMemory API.
-This is not yet standardised and browsers should not be expected to pass
-these tests.
+Tests in this directory are for the performance.measureMemory API:
 
-See the explainer at https://github.com/WICG/performance-measure-memory
-for more information about the API.
+- Specification: https://wicg.github.io/performance-measure-memory
+- Explainer: https://github.com/WICG/performance-measure-memory
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/detached.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/detached.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/detached.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/detached.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/idlharness.tentative.any.js b/third_party/blink/web_tests/external/wpt/measure-memory/idlharness.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/idlharness.tentative.any.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/idlharness.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.https.window.js.headers
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
rename to third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-site.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/main-frame.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/main-frame.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/main-frame.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.tentative.https.window.js
rename to third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.https.window.js.headers
similarity index 100%
copy from third_party/blink/web_tests/external/wpt/measure-memory/detached.tentative.https.window.js.headers
copy to third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.https.window.js.headers
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.tentative.https.window.js.headers b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.tentative.https.window.js.headers
deleted file mode 100644
index 4fff9d9..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.tentative.https.window.js.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-match.js b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-match.js
index 8bf7fda..60c0dd0 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-match.js
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-match.js
@@ -381,6 +381,7 @@
 cache_test(async (cache) => {
     const url = '/dummy';
     const original_type = 'text/html';
+    const override_type = 'text/plain';
     const init_with_headers = {
       headers: {
         'content-type': original_type
@@ -394,24 +395,22 @@
     assert_true(original_response_type.includes(original_type),
                 'original response should include the expected mime type');
 
-    // Verify overwriting the content-type header does not change the mime
-    // type.  It should be fixed at Response construction time.
+    // Verify overwriting the content-type header changes the mime type.
     const overwritten_response = new Response('hello world', init_with_headers);
-    overwritten_response.headers.set('content-type', 'text/plain');
+    overwritten_response.headers.set('content-type', override_type);
     const overwritten_response_type = (await overwritten_response.blob()).type;
-    assert_equals(overwritten_response_type, original_response_type,
-                  'original and overwritten response mime types should match');
+    assert_equals(overwritten_response_type, override_type,
+                  'mime type can be overridden');
 
     // Verify the Response read from Cache uses the original mime type
     // computed when it was first constructed.
     const tmp = new Response('hello world', init_with_headers);
-    tmp.headers.set('content-type', 'text/plain');
+    tmp.headers.set('content-type', override_type);
     await cache.put(url, tmp);
     const cache_response = await cache.match(url);
     const cache_mime_type = (await cache_response.blob()).type;
-    assert_equals(cache_mime_type, original_response_type,
-                  'original and cached overwritten response mime types ' +
-                  'should match');
-  }, 'MIME type should be frozen at response construction.');
+    assert_equals(cache_mime_type, override_type,
+                  'overwritten and cached response mime types should match');
+  }, 'MIME type should reflect Content-Type headers of response.');
 
 done();
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/serviceworker/cache-match.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/serviceworker/cache-match.https-expected.txt
new file mode 100644
index 0000000..2173cd8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/serviceworker/cache-match.https-expected.txt
@@ -0,0 +1,28 @@
+This is a testharness.js-based test.
+PASS Cache.match
+PASS Cache.match with no matching entries
+PASS Cache.match with URL
+PASS Cache.match with Request
+PASS Cache.match with multiple cache hits
+PASS Cache.match with new Request
+PASS Cache.match with HEAD
+PASS Cache.match with ignoreSearch option (request with no search parameters)
+PASS Cache.match with ignoreSearch option (request with search parameter)
+PASS Cache.match supports ignoreMethod
+PASS Cache.match supports ignoreVary
+PASS Cache.match does not support cacheName option
+PASS Cache.match with URL containing fragment
+PASS Cache.match with string fragment "http" as query
+PASS Cache.match with responses containing "Vary" header
+PASS Cache.match with Request and Response objects with different URLs
+PASS Cache.match invoked multiple times for the same Request/Response
+PASS Cache.match blob should be sliceable
+PASS Cache.match with POST Request
+PASS Cache.match with a non-2xx Response
+PASS Cache.match with a network error Response
+PASS Cache produces large Responses that can be cloned and read correctly.
+PASS cors-exposed header should be stored correctly.
+PASS MIME type should be set from content-header correctly.
+FAIL MIME type should reflect Content-Type headers of response. assert_equals: mime type can be overridden expected "text/plain" but got "text/html"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/window/cache-match.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/window/cache-match.https-expected.txt
new file mode 100644
index 0000000..502a117
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/window/cache-match.https-expected.txt
@@ -0,0 +1,27 @@
+This is a testharness.js-based test.
+PASS Cache.match with no matching entries
+PASS Cache.match with URL
+PASS Cache.match with Request
+PASS Cache.match with multiple cache hits
+PASS Cache.match with new Request
+PASS Cache.match with HEAD
+PASS Cache.match with ignoreSearch option (request with no search parameters)
+PASS Cache.match with ignoreSearch option (request with search parameter)
+PASS Cache.match supports ignoreMethod
+PASS Cache.match supports ignoreVary
+PASS Cache.match does not support cacheName option
+PASS Cache.match with URL containing fragment
+PASS Cache.match with string fragment "http" as query
+PASS Cache.match with responses containing "Vary" header
+PASS Cache.match with Request and Response objects with different URLs
+PASS Cache.match invoked multiple times for the same Request/Response
+PASS Cache.match blob should be sliceable
+PASS Cache.match with POST Request
+PASS Cache.match with a non-2xx Response
+PASS Cache.match with a network error Response
+PASS Cache produces large Responses that can be cloned and read correctly.
+PASS cors-exposed header should be stored correctly.
+PASS MIME type should be set from content-header correctly.
+FAIL MIME type should reflect Content-Type headers of response. assert_equals: mime type can be overridden expected "text/plain" but got "text/html"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/worker/cache-match.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/worker/cache-match.https-expected.txt
new file mode 100644
index 0000000..502a117
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/worker/cache-match.https-expected.txt
@@ -0,0 +1,27 @@
+This is a testharness.js-based test.
+PASS Cache.match with no matching entries
+PASS Cache.match with URL
+PASS Cache.match with Request
+PASS Cache.match with multiple cache hits
+PASS Cache.match with new Request
+PASS Cache.match with HEAD
+PASS Cache.match with ignoreSearch option (request with no search parameters)
+PASS Cache.match with ignoreSearch option (request with search parameter)
+PASS Cache.match supports ignoreMethod
+PASS Cache.match supports ignoreVary
+PASS Cache.match does not support cacheName option
+PASS Cache.match with URL containing fragment
+PASS Cache.match with string fragment "http" as query
+PASS Cache.match with responses containing "Vary" header
+PASS Cache.match with Request and Response objects with different URLs
+PASS Cache.match invoked multiple times for the same Request/Response
+PASS Cache.match blob should be sliceable
+PASS Cache.match with POST Request
+PASS Cache.match with a non-2xx Response
+PASS Cache.match with a network error Response
+PASS Cache produces large Responses that can be cloned and read correctly.
+PASS cors-exposed header should be stored correctly.
+PASS MIME type should be set from content-header correctly.
+FAIL MIME type should reflect Content-Type headers of response. assert_equals: mime type can be overridden expected "text/plain" but got "text/html"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/wasm/webapi/modified-contenttype.any.js b/third_party/blink/web_tests/external/wpt/wasm/webapi/modified-contenttype.any.js
new file mode 100644
index 0000000..35493051
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/wasm/webapi/modified-contenttype.any.js
@@ -0,0 +1,24 @@
+// META: global=window,worker
+// META: script=/wasm/jsapi/wasm-module-builder.js
+
+["compileStreaming", "instantiateStreaming"].forEach(method => {
+  promise_test(async t => {
+    const buffer = new WasmModuleBuilder().toBuffer();
+    const argument = new Response(buffer, { headers: { "Content-Type": "test/test" } });
+    argument.headers.set("Content-Type", "application/wasm");
+    // This should resolve successfully
+    await WebAssembly[method](argument);
+    // Ensure body can only be read once
+    return promise_rejects_js(t, TypeError, argument.blob());
+  }, `${method} with Content-Type set late`);
+
+  promise_test(async t => {
+    const buffer = new WasmModuleBuilder().toBuffer();
+    const argument = new Response(buffer, { headers: { "Content-Type": "application/wasm" } });
+    argument.headers.delete("Content-Type");
+    // Ensure Wasm cannot be created
+    await promise_rejects_js(t, TypeError, WebAssembly[method](argument));
+    // This should resolve successfully
+    await argument.arrayBuffer();
+  }, `${method} with Content-Type removed late`);
+});
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-iceRestart.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-iceRestart.html
new file mode 100644
index 0000000..648c11b6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-iceRestart.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCDataChannel interactions with ICE restart</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+async function checkCanPassData(channel1, channel2) {
+  channel1.send('hello');
+  const message = await awaitMessage(channel2);
+  assert_equals(message, 'hello');
+}
+
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+
+  const [channel1, channel2] = await createDataChannelPair(t, {}, pc1, pc2);
+  channel2.addEventListener('error', t.unreached_func());
+  channel2.addEventListener('error', t.unreached_func());
+
+  await checkCanPassData(channel1, channel2);
+  await checkCanPassData(channel2, channel1);
+
+  pc1.restartIce();
+  await exchangeOfferAnswer(pc1, pc2);
+
+  await checkCanPassData(channel1, channel2);
+  await checkCanPassData(channel2, channel1);
+  channel1.close();
+  channel2.close();
+}, `Data channel remains usable after ICE restart`);
+
+</script>
diff --git a/third_party/blink/web_tests/fast/scroll-behavior/middleclick-autoscroll-nested-elements.html b/third_party/blink/web_tests/fast/scroll-behavior/middleclick-autoscroll-nested-elements.html
new file mode 100644
index 0000000..aa82bb54
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scroll-behavior/middleclick-autoscroll-nested-elements.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src='../../resources/gesture-util.js'></script>
+<style>
+
+body {
+  height: 2000px;
+  width: 2000px;
+  background: repeating-linear-gradient(
+    45deg,
+    #606dbc,
+    #606dbc 40px,
+    #465298 40px,
+    #465298 80px
+  ) local;
+}
+
+#scroller {
+  width: 90px;
+  border: 2px solid black;
+  height: 90px;
+  position: absolute;
+  top: 50px;
+  overflow: auto;
+  background: repeating-linear-gradient(
+    135deg,
+    #bc6d60,
+    #bc6d60 40px,
+    #985246 40px,
+    #985246 80px
+  ) local;
+}
+
+#contents {
+  height: 200px;
+}
+
+</style>
+
+<div id="scroller">
+	<div id="contents"></div>
+</div>
+
+<script>
+
+var scroller = document.getElementById('scroller');
+
+promise_test(async () => {
+  assert_equals(scroller.scrollTop, 0);
+  await waitForCompositorCommit();
+  await mouseClickOn(12, 60, 1);
+  await mouseMoveTo(12, 260);
+  await mouseClickOn(12, 260, 1);
+  await waitFor(() => {
+    return scroller.scrollTop > 0;
+  }, "failed to scroll scroller vertically");
+}, "Middle click autoscroll should scroll child if child delta can be consumed.");
+
+promise_test(async () => {
+  assert_equals(document.scrollingElement.scrollLeft, 0)
+  await waitForCompositorCommit();
+  await mouseClickOn(12, 60, 1);
+  await mouseMoveTo(212, 60);
+  await mouseClickOn(212, 60, 1);
+  await waitFor(() => {
+    return document.scrollingElement.scrollLeft > 0;
+  }, "failed to scroll document body horizontally");
+}, "Middle click autoscroll should scroll parent if child delta can not be consumed.");
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/scrolling/autoscroll-iframe-no-scrolling.html b/third_party/blink/web_tests/fast/scrolling/autoscroll-iframe-no-scrolling.html
index 7e76fbf..1d68352 100644
--- a/third_party/blink/web_tests/fast/scrolling/autoscroll-iframe-no-scrolling.html
+++ b/third_party/blink/web_tests/fast/scrolling/autoscroll-iframe-no-scrolling.html
@@ -86,15 +86,14 @@
       // Autoscroll over the inner scroller.
       await autoScroll(startX, startY, endX, endY);
       await waitForAnimationEndTimeBased( () => { return window.scrollY; } );
-      assert_equals(window.scrollY, 0, "Main frame should not scroll");
+      assert_equals(frames[0].window.scrollY, 0, "Iframe frame should not scroll");
 
       // Autoscroll over the iframe.
       startX = rect.right - 20;
       endX = startX;
       await autoScroll(startX, startY, endX, endY);
       await waitForAnimationEndTimeBased( () => { return window.scrollY; } );
-      assert_equals(window.scrollY, 0, "Main frame should not scroll");
-
+      assert_true(window.scrollY > 0, "Main frame should not scroll");
       assert_equals(frames[0].window.scrollY, 0, "IFrame must NOT scroll.");
     });
 });
diff --git a/third_party/blink/web_tests/fast/scrolling/autoscroll-latch-clicked-node-if-parent-unscrollable.html b/third_party/blink/web_tests/fast/scrolling/autoscroll-latch-clicked-node-if-parent-unscrollable.html
new file mode 100644
index 0000000..2e5a335
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scrolling/autoscroll-latch-clicked-node-if-parent-unscrollable.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/gesture-util.js"></script>
+
+<style>
+  #container {
+    width:500px;
+    height:100px;
+    overflow:auto;
+    border:2px solid red;
+    padding:0px;
+  }
+  #spacer {
+    height:200px;
+  }
+</style>
+
+<ol>
+  <li>Middle-click inside the &lt;div&gt; with the red border below to activate autoscroll.</li>
+  <li>First, move the mouse such that you scroll the &lt;div&gt; in unavailable scroll direction and then in scrollable direction.</li>
+  <li>If bug repros, it won't scroll in available direction.</li>
+</ol>
+<div id="container">
+  <div id="spacer"></div>
+</div>
+
+<script>
+
+window.onload = async function()
+{
+    const container = document.getElementById("container");
+    const leftButton = 0;
+    const middleButton = 1;
+
+    promise_test (async (t) => {
+      await waitForCompositorCommit();
+      await mouseClickOn(container.offsetLeft + 10, container.offsetTop + 10, middleButton);
+      //Move mouse in unavailable direction first.
+      await mouseMoveTo(container.offsetLeft + (container.offsetWidth/2), container.offsetTop + 10);
+      //Move mouse in available direction to scroll the content.
+      await mouseMoveTo(container.offsetLeft + (container.offsetWidth/2), container.offsetTop + container.offsetHeight);
+
+      await waitFor(() => {
+        return container.scrollTop === container.scrollHeight - container.clientHeight;
+      }, "Failed to scroll container with middle-click autoscroll.");
+    }, "Container scrolled in available direction.");
+}
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/utilities-expected.txt b/third_party/blink/web_tests/http/tests/devtools/components/utilities-expected.txt
deleted file mode 100644
index 7bc90f76..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/components/utilities-expected.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-This test checks Web Inspector utilities.
-
-
-Running: orderedMergeIntersect
-
-Running: lowerBoundTest
-
-Running: upperBoundTest
-
-Running: sortRangeTest
-
-Running: naturalOrderComparatorTest
-Sorted in natural order: [1, 2, 2, 2, 5, 10, 11, 5555, 555555, a1, a007, a07, a7, a91, a4222, abc, abc0, abc00, abc000, abcd, dup, dup, dup, dup, dup, x09y19z29, x9y19z29, x10y19z43, x10y20z30, x10y22z23]
-
-Running: stringHashTest
-
-Running: trimMiddle
-
-!
-!
-🙈A🙈L🙈I🙈N🙈A🙈🙈
-🙈A🙈L🙈I🙈N🙈A🙈🙈
-🙈A🙈L🙈I…N🙈A🙈🙈
-🙈A🙈L🙈…N🙈A🙈🙈
-🙈A🙈L🙈…🙈A🙈🙈
-🙈A🙈L…🙈A🙈🙈
-🙈A🙈L🙈…A🙈🙈
-🙈A🙈L…A🙈🙈
-🙈A🙈L…A🙈🙈
-🙈A🙈…A🙈🙈
-🙈A🙈…🙈🙈
-🙈A…🙈🙈
-🙈A🙈…🙈
-🙈A…🙈
-🙈A…🙈
-🙈…🙈
-🙈A…
-🙈…
-…
-…
-test
-test
-t…t
-t…
-…
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/components/utilities.js b/third_party/blink/web_tests/http/tests/devtools/components/utilities.js
deleted file mode 100644
index cfc5a83..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/components/utilities.js
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2017 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.
-
-(async function() {
-  'use strict';
-  TestRunner.addResult(`This test checks Web Inspector utilities.\n`);
-
-
-  TestRunner.runTestSuite([
-    function orderedMergeIntersect(next) {
-      function comparator(a, b) {
-        return a - b;
-      }
-      function count(a, x) {
-        return a.upperBound(x) - a.lowerBound(x);
-      }
-      function testAll(a, b) {
-        testOperation(a, b, a.mergeOrdered(b, comparator), Math.max, 'U');
-        testOperation(a, b, a.intersectOrdered(b, comparator), Math.min, 'x');
-      }
-      function testOperation(a, b, actual, checkOperation, opName) {
-        var allValues = a.concat(b).concat(actual);
-        for (var i = 0; i < allValues.length; ++i) {
-          var value = allValues[i];
-          const expectedCount =
-              checkOperation(count(a, value), count(b, value));
-          const actualCount = count(actual, value);
-          TestRunner.assertEquals(
-              expectedCount, actualCount,
-              'Incorrect result for value: ' + value + ' at [' + a + '] ' + opName + ' [' + b + '] -> [' + actual +
-                  ']');
-        }
-        TestRunner.assertEquals(JSON.stringify(actual.sort()), JSON.stringify(actual), 'result array is ordered');
-      }
-      var testArrays = [
-        [], [], [1], [], [1, 2, 2, 2, 3], [], [4, 5, 5, 8, 8], [1, 1, 1, 2, 6], [1, 2, 2, 2, 2, 3, 3, 4],
-        [2, 2, 2, 3, 3, 3, 3], [1, 2, 3, 4, 5], [1, 2, 3]
-      ];
-      for (var i = 0; i < testArrays.length; i += 2) {
-        testAll(testArrays[i], testArrays[i + 1]);
-        testAll(testArrays[i + 1], testArrays[i]);
-      }
-      next();
-    },
-
-    function lowerBoundTest(next) {
-      var testArrays = [[], [1], [-1, -1, 0, 0, 0, 0, 2, 3, 4, 4, 4, 7, 9, 9, 9]];
-
-      function testArray(array, useComparator) {
-        function comparator(a, b) {
-          return a < b ? -1 : (a > b ? 1 : 0);
-        }
-
-        for (var value = -2; value <= 12; ++value) {
-          var index = useComparator ? array.lowerBound(value, comparator) : array.lowerBound(value);
-          TestRunner.assertTrue(0 <= index && index <= array.length, 'index is within bounds');
-          TestRunner.assertTrue(index === 0 || array[index - 1] < value, 'array[index - 1] < value');
-          TestRunner.assertTrue(index === array.length || array[index] >= value, 'array[index] >= value');
-        }
-      }
-
-      for (var i = 0, l = testArrays.length; i < l; ++i) {
-        testArray(testArrays[i], false);
-        testArray(testArrays[i], true);
-      }
-      next();
-    },
-
-    function upperBoundTest(next) {
-      var testArrays = [[], [1], [-1, -1, 0, 0, 0, 0, 2, 3, 4, 4, 4, 7, 9, 9, 9]];
-
-      function testArray(array, useComparator) {
-        function comparator(a, b) {
-          return a < b ? -1 : (a > b ? 1 : 0);
-        }
-
-        for (var value = -2; value <= 12; ++value) {
-          var index = useComparator ? array.upperBound(value, comparator) : array.upperBound(value);
-          TestRunner.assertTrue(0 <= index && index <= array.length, 'index is within bounds');
-          TestRunner.assertTrue(index === 0 || array[index - 1] <= value, 'array[index - 1] <= value');
-          TestRunner.assertTrue(index === array.length || array[index] > value, 'array[index] > value');
-        }
-      }
-
-      for (var i = 0, l = testArrays.length; i < l; ++i) {
-        testArray(testArrays[i], false);
-        testArray(testArrays[i], true);
-      }
-      next();
-    },
-
-    function sortRangeTest(next) {
-      var testArrays = [[], [1], [2, 1], [6, 4, 2, 7, 10, 15, 1], [10, 44, 3, 6, 56, 66, 10, 55, 32, 56, 2, 5]];
-
-      function testArray(array) {
-        function comparator(a, b) {
-          return a < b ? -1 : (a > b ? 1 : 0);
-        }
-
-        function compareArrays(a, b, message) {
-          TestRunner.assertEquals(JSON.stringify(a), JSON.stringify(b), message);
-        }
-
-        for (var left = 0, l = array.length - 1; left < l; ++left) {
-          for (var right = left, r = array.length; right < r; ++right) {
-            for (var first = left; first <= right; ++first) {
-              for (var count = 1, k = right - first + 1; count <= k; ++count) {
-                var actual = array.slice(0);
-                actual.sortRange(comparator, left, right, first, first + count - 1);
-                compareArrays(array.slice(0, left), actual.slice(0, left), 'left ' + left + ' ' + right + ' ' + count);
-                compareArrays(
-                    array.slice(right + 1), actual.slice(right + 1), 'right ' + left + ' ' + right + ' ' + count);
-                var middle = array.slice(left, right + 1);
-                middle.sort(comparator);
-                compareArrays(
-                    middle.slice(first - left, first - left + count), actual.slice(first, first + count),
-                    'sorted ' + left + ' ' + right + ' ' + first + ' ' + count);
-                const actualRest = actual.slice(first + count, right + 1);
-                actualRest.sort(comparator);
-                compareArrays(
-                    middle.slice(first - left + count), actualRest,
-                    'unsorted ' + left + ' ' + right + ' ' + first + ' ' + count);
-              }
-            }
-          }
-        }
-      }
-
-      for (var i = 0, len = testArrays.length; i < len; ++i)
-        testArray(testArrays[i]);
-      next();
-    },
-
-    function naturalOrderComparatorTest(next) {
-      var testArray = [
-        'dup', 'a1',   'a4222',  'a91',       'a07',      'dup', 'a7',        'a007',      'abc00',     'abc0',
-        'abc', 'abcd', 'abc000', 'x10y20z30', 'x9y19z29', 'dup', 'x09y19z29', 'x10y22z23', 'x10y19z43', '1',
-        '10',  '11',   'dup',    '2',         '2',        '2',   '555555',    '5',         '5555',      'dup',
-      ];
-
-      for (var i = 0, n = testArray.length; i < n; ++i)
-        TestRunner.assertEquals(
-            0, String.naturalOrderComparator(testArray[i], testArray[i]), 'comparing equal strings');
-
-      testArray.sort(String.naturalOrderComparator);
-      TestRunner.addResult('Sorted in natural order: [' + testArray.join(', ') + ']');
-
-      // Check comparator's transitivity.
-      for (var i = 0, n = testArray.length; i < n; ++i) {
-        for (var j = 0; j < n; ++j) {
-          var a = testArray[i];
-          var b = testArray[j];
-          var diff = String.naturalOrderComparator(a, b);
-          if (diff === 0)
-            TestRunner.assertEquals(a, b, 'zero diff');
-          else if (diff < 0)
-            TestRunner.assertTrue(i < j);
-          else
-            TestRunner.assertTrue(i > j);
-        }
-      }
-      next();
-    },
-
-    function stringHashTest(next) {
-      var stringA = ' '.repeat(10000);
-      var stringB = stringA + ' ';
-      var hashA = String.hashCode(stringA);
-      TestRunner.assertTrue(hashA !== String.hashCode(stringB));
-      TestRunner.assertTrue(isFinite(hashA));
-      TestRunner.assertTrue(hashA + 1 !== hashA);
-      next();
-    },
-
-    function trimMiddle(next) {
-      var testArray = [
-        '', '!', '\uD83D\uDE48A\uD83D\uDE48L\uD83D\uDE48I\uD83D\uDE48N\uD83D\uDE48A\uD83D\uDE48\uD83D\uDE48', 'test'
-      ];
-      for (var string of testArray) {
-        for (var maxLength = string.length + 1; maxLength > 0; --maxLength) {
-          var trimmed = string.trimMiddle(maxLength);
-          TestRunner.addResult(trimmed);
-          TestRunner.assertTrue(trimmed.length <= maxLength);
-        }
-      }
-      next();
-    }
-  ]);
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation-expected.txt
index 1134b7e..c5f87de3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation-expected.txt
@@ -1,5 +1,5 @@
 Tests that the console can preserve log messages across cross-process navigations.
-console-preserve-log…ss-navigation.js:11 before navigation
-Navigated to empty.html
-console-preserve-log…ss-navigation.js:13 after navigation
+log-message.html:5 before navigation
+Navigated to log-message.html
+log-message.html:5 after navigation
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
index 62f2ee8..d3fd3346 100644
--- a/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
+++ b/third_party/blink/web_tests/http/tests/devtools/console/console-preserve-log-x-process-navigation.js
@@ -6,11 +6,11 @@
   TestRunner.addResult(`Tests that the console can preserve log messages across cross-process navigations.`);
   await TestRunner.loadModule('console_test_runner');
   await TestRunner.showPanel('console');
-  await TestRunner.navigatePromise('http://devtools.oopif.test:8000/devtools/oopif/resources/empty.html')
+  await TestRunner.navigatePromise('http://devtools.oopif.test:8000/devtools/console/resources/log-message.html')
   Common.settingForTest('preserveConsoleLog').set(true);
-  await TestRunner.evaluateInPage(`console.log('before navigation')`);
-  await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/oopif/resources/empty.html')
-  await TestRunner.evaluateInPage(`console.log('after navigation')`);
+  await TestRunner.evaluateInPage(`logMessage('before navigation')`);
+  await TestRunner.navigatePromise('http://127.0.0.1:8000/devtools/console/resources/log-message.html')
+  await TestRunner.evaluateInPage(`logMessage('after navigation')`);
   await ConsoleTestRunner.dumpConsoleMessages();
   TestRunner.completeTest();
 })();
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/resources/log-message.html b/third_party/blink/web_tests/http/tests/devtools/console/resources/log-message.html
new file mode 100644
index 0000000..48df00f
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/console/resources/log-message.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<body>
+  <script>
+    function logMessage(message) {
+      console.log(message);
+    }
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-resource-referred-by-multiple-styletags.js b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-resource-referred-by-multiple-styletags.js
index d7b7c268e..a02c04d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-resource-referred-by-multiple-styletags.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-resource-referred-by-multiple-styletags.js
@@ -56,6 +56,6 @@
       return;
     }
     TestRunner.addResult('Both headers and uiSourceCode content:');
-    TestRunner.addResult(dedup.firstValue());
+    TestRunner.addResult(dedup.size ? dedup.values().next().value : null);
   }
 })();
diff --git a/third_party/blink/web_tests/platform/linux/compositing/reflections/nested-reflection-animated-expected.png b/third_party/blink/web_tests/platform/linux/compositing/reflections/nested-reflection-animated-expected.png
index 89439e4..766501ce 100644
--- a/third_party/blink/web_tests/platform/linux/compositing/reflections/nested-reflection-animated-expected.png
+++ b/third_party/blink/web_tests/platform/linux/compositing/reflections/nested-reflection-animated-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
deleted file mode 100644
index f605ffa..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
deleted file mode 100644
index f7a5ff2..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
deleted file mode 100644
index ffe3813..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
deleted file mode 100644
index cb4cc2b0..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
deleted file mode 100644
index 3209d53..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
deleted file mode 100644
index 01fd3cd0..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
deleted file mode 100644
index fade0fb5..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
deleted file mode 100644
index 65885e1..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
deleted file mode 100644
index 026b36f..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-object-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-object-expected.png
deleted file mode 100644
index 848aca5..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-object-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
deleted file mode 100644
index f7a5ff2..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
deleted file mode 100644
index ffe3813..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
index eccb194..cb230c1 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
index ddb1e69..0af66ee 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
index 58346d3..fbbb309 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
deleted file mode 100644
index cb4cc2b0..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
index f7caf7d..2e58693 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
index f7caf7d..2e58693 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
deleted file mode 100644
index 3209d53..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
deleted file mode 100644
index 01fd3cd0..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
deleted file mode 100644
index fade0fb5..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
deleted file mode 100644
index 65885e1..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
deleted file mode 100644
index 026b36f..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-object-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-object-expected.png
deleted file mode 100644
index 848aca5..0000000
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-object-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
index ddb1e69..0af66ee 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
index 58346d3..fbbb309 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/compositing/reflections/nested-reflection-animated-expected.png b/third_party/blink/web_tests/platform/win/compositing/reflections/nested-reflection-animated-expected.png
index 4f58820..8d7857e 100644
--- a/third_party/blink/web_tests/platform/win/compositing/reflections/nested-reflection-animated-expected.png
+++ b/third_party/blink/web_tests/platform/win/compositing/reflections/nested-reflection-animated-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
index f605ffa..2911490 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
index f7a5ff2..17f2233d 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
index ffe3813..b3adb7a 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
deleted file mode 100644
index cb4cc2b0..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
index 3bfc58a6..22971fe 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
index 3bfc58a6..22971fe 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
deleted file mode 100644
index 3209d53..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
deleted file mode 100644
index 01fd3cd0..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
deleted file mode 100644
index fade0fb5..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
deleted file mode 100644
index 65885e1..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
deleted file mode 100644
index 026b36f..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-object-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-object-expected.png
deleted file mode 100644
index 848aca5..0000000
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-object-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
index f7a5ff2..17f2233d 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
index ffe3813..b3adb7a 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
deleted file mode 100644
index f605ffa..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-border-radius-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
deleted file mode 100644
index f7a5ff2..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-filter-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
deleted file mode 100644
index ffe3813..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
deleted file mode 100644
index cb4cc2b0..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
deleted file mode 100644
index 3209d53..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
deleted file mode 100644
index 01fd3cd0..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
deleted file mode 100644
index fade0fb5..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
deleted file mode 100644
index 65885e1..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
deleted file mode 100644
index 026b36f..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-object-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-object-expected.png
deleted file mode 100644
index 848aca5..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-object-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
deleted file mode 100644
index f7a5ff2..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-filter-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
deleted file mode 100644
index ffe3813..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
new file mode 100644
index 0000000..2715102e
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
new file mode 100644
index 0000000..64fa6f4
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
new file mode 100644
index 0000000..4eb022c
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
index d035c14a..f83899f 100644
--- a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
new file mode 100644
index 0000000..200168c
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
new file mode 100644
index 0000000..e492aa9a
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png
index acf2133..c9069e3 100644
--- a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-object-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-object-expected.png
new file mode 100644
index 0000000..5e115ce
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/shaka-player/LICENSE b/third_party/shaka-player/LICENSE
deleted file mode 100644
index eff80c2..0000000
--- a/third_party/shaka-player/LICENSE
+++ /dev/null
@@ -1,227 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
------
-
-Contains code from https://github.com/mozilla/language-mapping-list
-
-The MIT License (MIT)
-
-Copyright (c) 2013 Ali Al Dallal
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/third_party/shaka-player/OWNERS b/third_party/shaka-player/OWNERS
deleted file mode 100644
index e4ffdff8..0000000
--- a/third_party/shaka-player/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-beccahughes@chromium.org
-steimel@chromium.org
diff --git a/third_party/shaka-player/README.chromium b/third_party/shaka-player/README.chromium
deleted file mode 100644
index 487e012a..0000000
--- a/third_party/shaka-player/README.chromium
+++ /dev/null
@@ -1,14 +0,0 @@
-Name: Shaka Player
-Short Name: shaka-player
-URL: https://github.com/google/shaka-player
-Version: 3.0.4
-License: Apache 2.0
-License File: LICENSE
-Security Critical: Yes
-Description:
-Shaka Player is an open-source JavaScript library for adaptive media. It is used
-by Chrome Kaleidoscope to play video content in the UI that uses DASH.
-
-Local Modifications:
-None. Take the most recent version from the official releases page:
-https://github.com/google/shaka-player/releases
diff --git a/third_party/shaka-player/cipd.yaml b/third_party/shaka-player/cipd.yaml
deleted file mode 100644
index c3d9e6b3..0000000
--- a/third_party/shaka-player/cipd.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-# To create CIPD package run the following command.
-# cipd create --pkg-def cipd.yaml
-package: chromium/third_party/shaka-player
-description: Shaka Player
-root: ./dist
-install_mode: copy
-data:
-  - file: package.json
-  - file: shaka-player.ui.externs.js
-  - file: shaka-player.ui.js
-  - file: shaka-player.ui.map
-  - file: wrapper.js
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index ee3396e3..a7e9e7a 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -317,9 +317,9 @@
   """Download a modern GCC host compiler on Linux."""
   if not sys.platform.startswith('linux') or args.gcc_toolchain:
     return
-  gcc_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gcc530trusty')
+  gcc_dir = os.path.join(LLVM_BUILD_TOOLS_DIR, 'gcc-10.2.0-trusty')
   if not os.path.exists(gcc_dir):
-    DownloadAndUnpack(CDS_URL + '/tools/gcc530trusty.tgz', gcc_dir)
+    DownloadAndUnpack(CDS_URL + '/tools/gcc-10.2.0-trusty.tgz', gcc_dir)
   args.gcc_toolchain = gcc_dir
 
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index a30a4f5..22434c3 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -217,7 +217,6 @@
       'ToTWinThinLTO64': 'clang_tot_win_official_full_symbols_thin_lto_static',
       'ToTiOS': 'ios_clang_tot_xctest',
       'ToTiOSDevice': 'ios_clang_device_tot_xctest',
-      'UBSanVptr Linux': 'ubsan_vptr_release_bot',
     },
 
     'chromium.dawn': {
diff --git a/tools/mb/mb_config_expectations/chromium.clang.json b/tools/mb/mb_config_expectations/chromium.clang.json
index 5dd34ef..1a0392c 100644
--- a/tools/mb/mb_config_expectations/chromium.clang.json
+++ b/tools/mb/mb_config_expectations/chromium.clang.json
@@ -434,15 +434,6 @@
       "target_os": "ios"
     }
   },
-  "UBSanVptr Linux": {
-    "gn_args": {
-      "is_component_build": false,
-      "is_debug": false,
-      "is_ubsan_no_recover": true,
-      "is_ubsan_vptr": true,
-      "use_goma": true
-    }
-  },
   "linux-win_cross-rel": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 2bcb0b9..9d07b6b 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -5893,6 +5893,32 @@
   </description>
 </action>
 
+<action name="DesktopReadingList.AddItem.FromBookmarkIcon">
+  <owner>corising@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    The user added to the reading list from the Bookmark icon entry point
+    (Desktop only).
+  </description>
+</action>
+
+<action name="DesktopReadingList.AddItem.FromTabContextMenu">
+  <owner>corising@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    The user added to the reading list from the tab context menu entry point
+    (Desktop only).
+  </description>
+</action>
+
+<action name="DesktopReadingList.OpenReadingList">
+  <owner>corising@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    The user clicked the Desktop reading list button to open the reading list.
+  </description>
+</action>
+
 <action name="DesktopSearch">
   <obsolete>
     Deprecated 05/2016 because desktop searches are no longer opened in the
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 6007237..d6e2196 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -10383,6 +10383,10 @@
   <int value="58" label="SelectSidenavOutline"/>
   <int value="59" label="ToggleDisplayAnnotationsFirst"/>
   <int value="60" label="ToggleDisplayAnnotations"/>
+  <int value="61" label="PresentFirst"/>
+  <int value="62" label="Present"/>
+  <int value="63" label="PropertiesFirst"/>
+  <int value="64" label="Properties"/>
 </enum>
 
 <enum name="ChromePDFViewerAnnotationType">
@@ -24299,6 +24303,9 @@
   <int value="467"
       label="ACCESSIBILITY_PRIVATE_ON_SELECT_TO_SPEAK_PANEL_ACTION"/>
   <int value="468" label="FILE_MANAGER_PRIVATE_ON_TABLET_MODE_CHANGED"/>
+  <int value="469"
+      label="VIRTUAL_KEYBOARD_PRIVATE_ON_CLIPBOARD_HISTORY_CHANGED"/>
+  <int value="470" label="VIRTUAL_KEYBOARD_PRIVATE_ON_CLIPBOARD_ITEM_UPDATED"/>
 </enum>
 
 <enum name="ExtensionFileWriteResult">
@@ -30838,6 +30845,7 @@
   <int value="3749" label="EmbedElementWithoutTypeSrcChanged"/>
   <int value="3750" label="PaymentHandlerStandardizedPaymentMethodIdentifier"/>
   <int value="3751" label="WebCodecsAudioEncoder"/>
+  <int value="3752" label="EmbeddedCrossOriginFrameWithoutFrameAncestorsOrXFO"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -32977,6 +32985,7 @@
   <int value="0" label="Gaia cookie is present"/>
   <int value="1" label="Gaia cookie is missing from Google-associated domain"/>
   <int value="2" label="Gaia cookie is missing from Add Session"/>
+  <int value="3" label="Gaia cookie is restored, Infobar shown"/>
 </enum>
 
 <enum name="GaiaPasswordChangedScreenUserAction">
@@ -43452,6 +43461,7 @@
   <int value="-1033738911" label="enable-mac-views-dialogs"/>
   <int value="-1032884201" label="HeavyAdPrivacyMitigations:enabled"/>
   <int value="-1031350684" label="PdfIsolation:disabled"/>
+  <int value="-1030530357" label="PwaInstallUseBottomSheet:disabled"/>
   <int value="-1029920490" label="IdleTimeSpellChecking:enabled"/>
   <int value="-1028733699" label="MacViewsWebUIDialogs:disabled"/>
   <int value="-1028251580" label="GamepadPollingInterval:disabled"/>
@@ -46671,6 +46681,7 @@
   <int value="2049432745" label="VaapiWebPImageDecodeAcceleration:enabled"/>
   <int value="2050985807" label="AllowPopupsDuringPageUnload:enabled"/>
   <int value="2051403297" label="ShowBluetoothDeviceBattery:disabled"/>
+  <int value="2051886966" label="PwaInstallUseBottomSheet:enabled"/>
   <int value="2056572020" label="EnableUsernameCorrection:disabled"/>
   <int value="2058148069" label="UseMessagesStagingUrl:enabled"/>
   <int value="2058283872" label="CCTModuleCache:disabled"/>
@@ -61572,6 +61583,7 @@
   <int value="1" label="kBrowserWindow"/>
   <int value="2" label="kBackgroundMode"/>
   <int value="3" label="kOffTheRecordProfile"/>
+  <int value="4" label="kDownloadInProgress"/>
 </enum>
 
 <enum name="ProfileMenuActionableItem">
@@ -64097,6 +64109,17 @@
   <int value="14" label="User refused to terminate process"/>
 </enum>
 
+<enum name="RemotingCompatibility">
+  <int value="0" label="Compatible"/>
+  <int value="1" label="Incompatible, no audio nor video"/>
+  <int value="2" label="Incompatible, encrypted video"/>
+  <int value="3" label="Incompatible video codec"/>
+  <int value="4" label="Incompatible, encrypted audio"/>
+  <int value="5" label="Incompatible audio codec"/>
+  <int value="6" label="Incompatible, disabled by page"/>
+  <int value="7" label="Incompatible, duration below threshold"/>
+</enum>
+
 <enum name="RemotingStartTrigger">
   <int value="0" label="Unknown start trigger"/>
   <int value="1" label="Entered fullscreen"/>
@@ -64139,6 +64162,19 @@
   <int value="3" label="Audio and video"/>
 </enum>
 
+<enum name="RemotingVideoPixelRateSupport">
+  <int value="0"
+      label="Supported; pixels-per-second is equivalent to at most 1080p
+             30fps"/>
+  <int value="1"
+      label="Supported; equivalent to more than 1080p 30fps and at most 2160p
+             30fps"/>
+  <int value="2"
+      label="Not supported; equivalent to more than 1080p 30fps and at most
+             2160p 30fps"/>
+  <int value="3" label="Not supported; equivalent to more than 2160p 30fps"/>
+</enum>
+
 <enum name="RemoveCompromisedCredentialsReason">
   <int value="0" label="Update - If the credentials was updated."/>
   <int value="1" label="Remove - If the credentials was removed."/>
@@ -71390,6 +71426,13 @@
   <int value="20" label="OTHER"/>
 </enum>
 
+<enum name="StarEntryPointAction">
+  <int value="0" label="Add bookmark"/>
+  <int value="1" label="Edit bookmark"/>
+  <int value="2" label="Add to reading list"/>
+  <int value="3" label="Mark as read"/>
+</enum>
+
 <enum name="StarsLaunchLocation">
   <obsolete>
     Removed 01/2020 as we no longer record this metric.
diff --git a/tools/metrics/histograms/histograms_xml/apps/histograms.xml b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
index 6b477d0..3a07ff4 100644
--- a/tools/metrics/histograms/histograms_xml/apps/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
@@ -1753,7 +1753,7 @@
 </histogram>
 
 <histogram name="Apps.StateTransition.AnimationSmoothness" units="%"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
 <!-- Name completed by histogram_suffixes
      name="TabletOrClamshellMode" and
      name="EnterOrExitOverview" and
diff --git a/tools/metrics/histograms/histograms_xml/ash/histograms.xml b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
index d2421b86..21178092 100644
--- a/tools/metrics/histograms/histograms_xml/ash/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
@@ -1035,7 +1035,7 @@
   <owner>tellier@google.com</owner>
   <owner>cros-oac@google.com</owner>
   <summary>
-    The count of auth method switching actions in ChromeOS lock screen.
+    The count of auth method switching actions on ChromeOS lock screen.
   </summary>
 </histogram>
 
@@ -1046,7 +1046,8 @@
   <owner>cros-oac@google.com</owner>
   <summary>
     The usage of different auth methods (PIN / Password / Smartlock /
-    Fingerprint / Challenge response) in ChromeOS lock screen clamshell mode.
+    Fingerprint / Challenge response) on Chromebooks in clamshell mode and on
+    other form-factors.
   </summary>
 </histogram>
 
@@ -1057,7 +1058,7 @@
   <owner>cros-oac@google.com</owner>
   <summary>
     The usage of different auth methods (PIN / Password / Smartlock /
-    Fingerprint / Challenge response) in ChromeOS lock screen tablet mode.
+    Fingerprint / Challenge response) on Chromebooks in tablet mode.
   </summary>
 </histogram>
 
@@ -1092,6 +1093,39 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.Login.Login.AuthMethod.Switched"
+    enum="AuthMethodSwitchType" expires_after="2021-05-16">
+  <owner>rsorokin@chromium.org</owner>
+  <owner>tellier@google.com</owner>
+  <owner>cros-oac@google.com</owner>
+  <summary>
+    The count of auth method switching actions on ChromeOS login screen.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Login.Login.AuthMethod.Used.ClamShellMode"
+    enum="AuthMethod" expires_after="2021-05-16">
+  <owner>rsorokin@chromium.org</owner>
+  <owner>tellier@google.com</owner>
+  <owner>cros-oac@google.com</owner>
+  <summary>
+    The usage of different auth methods (PIN / Password / Smartlock /
+    Fingerprint / Challenge response) on Chromebooks in clamshell mode and on
+    other form-factors.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Login.Login.AuthMethod.Used.TabletMode" enum="AuthMethod"
+    expires_after="2021-05-16">
+  <owner>rsorokin@chromium.org</owner>
+  <owner>tellier@google.com</owner>
+  <owner>cros-oac@google.com</owner>
+  <summary>
+    The usage of different auth methods (PIN / Password / Smartlock /
+    Fingerprint / Challenge response) on Chromebooks in tablet mode.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Login.Login.MigrationBanner" enum="BooleanShown"
     expires_after="2021-05-16">
   <owner>rsorokin@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
index f4bb1a74..cb2e1243 100644
--- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -519,6 +519,9 @@
 
 <histogram name="Blink.CookieStore.MatchType" enum="CookieStoreMatchType"
     expires_after="M87">
+  <obsolete>
+    Removed in M87.
+  </obsolete>
   <owner>ayui@chromium.org</owner>
   <owner>pwnall@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
index bd360eaf..d7ad3c5 100644
--- a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
@@ -206,7 +206,7 @@
 </histogram>
 
 <histogram name="Cryptohome.Errors" enum="CryptohomeError"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>Cryptohome errors.</summary>
@@ -384,7 +384,7 @@
 </histogram>
 
 <histogram name="Cryptohome.ParallelTasks" units="count"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>zuan@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>
@@ -523,7 +523,7 @@
 </histogram>
 
 <histogram name="Cryptohome.TimeToTakeTpmOwnership" units="ms"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>
@@ -541,7 +541,7 @@
   </summary>
 </histogram>
 
-<histogram name="CryptohomeClient" units="ms" expires_after="2021-05-09">
+<histogram name="CryptohomeClient" units="ms" expires_after="2021-07-11">
   <owner>zuan@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml b/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml
index 7e89a29..f49cf20 100644
--- a/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml
@@ -35,7 +35,7 @@
 </histogram>
 
 <histogram name="CustomTabs.ClientAppId" enum="ClientAppId"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>yusufo@chromium.org</owner>
   <summary>
     Android: AppId declared by the launching application in EXTRA_APPLICATION_ID
diff --git a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
index 36bcf7a..5b537a3 100644
--- a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
@@ -361,7 +361,7 @@
 </histogram>
 
 <histogram name="DataReductionProxy.StartupState"
-    enum="DataReductionProxyStartupState" expires_after="2021-05-09">
+    enum="DataReductionProxyStartupState" expires_after="2021-07-11">
   <owner>rajendrant@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
index 4eeb1eb..cd8d67b 100644
--- a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
@@ -279,7 +279,7 @@
 </histogram>
 
 <histogram name="Enterprise.CloudReportingBasicRequestSize" units="KB"
-    expires_after="2021-02-01">
+    expires_after="2022-02-01">
   <owner>zmin@chromium.org</owner>
   <owner>pastarmovj@chromium.org</owner>
   <summary>
@@ -290,7 +290,7 @@
 </histogram>
 
 <histogram name="Enterprise.CloudReportingRequestCount" units="requests"
-    expires_after="2021-02-01">
+    expires_after="2022-02-01">
   <owner>zmin@chromium.org</owner>
   <owner>pastarmovj@chromium.org</owner>
   <summary>
@@ -300,7 +300,7 @@
 </histogram>
 
 <histogram name="Enterprise.CloudReportingRequestSize" units="KB"
-    expires_after="2021-02-01">
+    expires_after="2022-02-01">
   <owner>zmin@chromium.org</owner>
   <owner>pastarmovj@chromium.org</owner>
   <summary>
@@ -310,7 +310,7 @@
 </histogram>
 
 <histogram name="Enterprise.CloudReportingResponse"
-    enum="EnterpriseCloudReportingResponse" expires_after="2021-02-01">
+    enum="EnterpriseCloudReportingResponse" expires_after="2022-02-01">
   <owner>zmin@chromium.org</owner>
   <owner>pastarmovj@chromium.org</owner>
   <summary>
@@ -948,7 +948,7 @@
 </histogram>
 
 <histogram name="Enterprise.OnBulkDataEntry.DataSize" units="bytes"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/event/histograms.xml b/tools/metrics/histograms/histograms_xml/event/histograms.xml
index ebdeb03..51fec7b 100644
--- a/tools/metrics/histograms/histograms_xml/event/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/event/histograms.xml
@@ -344,7 +344,7 @@
 </histogram>
 
 <histogram name="Event.Latency.HitTest" units="microseconds"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>schenney@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
@@ -363,7 +363,7 @@
 </histogram>
 
 <histogram name="Event.Latency.HitTestRecursive" units="microseconds"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>schenney@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/gcm/histograms.xml b/tools/metrics/histograms/histograms_xml/gcm/histograms.xml
index 567c98f..b9416bb 100644
--- a/tools/metrics/histograms/histograms_xml/gcm/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/gcm/histograms.xml
@@ -304,7 +304,7 @@
 </histogram>
 
 <histogram name="GCM.RegistrationRequestStatus"
-    enum="GCMRegistrationRequestStatus" expires_after="2021-05-09">
+    enum="GCMRegistrationRequestStatus" expires_after="2021-07-11">
   <owner>peter@chromium.org</owner>
   <summary>
     Status code of the outcome of a GCM registration request. The Unknown error
diff --git a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
index e696a5f..5f2bf10 100644
--- a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
@@ -42,56 +42,65 @@
 </histogram>
 
 <histogram name="GPU.ANGLE.D3D11CreateDeviceError" enum="Hresult"
-    expires_after="M90">
-  <owner>jmadill@chromium.org</owner>
+    expires_after="2021-06-30">
+  <owner>jonahr@google.com</owner>
+  <owner>angle-team@google.com</owner>
   <summary>
-    An extended Windows error code returned from D3D11CreateDevice on error. Can
-    be almost any valid HRESULT or DXGI error code, which are listed at
+    An extended Windows error code returned from D3D11CreateDevice on error when
+    ANGLE's D3D backend is in use. Can be almost any valid HRESULT or DXGI error
+    code, which are listed at
     https://msdn.microsoft.com/en-us/library/windows/desktop/bb509553.aspx.
   </summary>
 </histogram>
 
 <histogram name="GPU.ANGLE.D3D11FeatureLevel" enum="D3DFeatureLevel"
-    expires_after="M90">
-  <owner>jmadill@chromium.org</owner>
+    expires_after="2021-06-30">
+  <owner>jonahr@google.com</owner>
+  <owner>angle-team@google.com</owner>
   <summary>
     The maxmium supported (or currently requested) Direct3D feature level in
     D3D11 ANGLE. We support as low as 9.3, and as high as 11.1, though Chrome
     should only use 10.0+ for D3D11. Gives an indication of how new a user's
     video card is, what features it supports, and it's general speed tier.
+    Recorded on D3D device initialization, loss, or reset when ANGLE's D3D
+    backend is in use.
   </summary>
 </histogram>
 
 <histogram name="GPU.ANGLE.D3D11InitializeResult" enum="D3D11InitializeResult"
-    expires_after="2020-11-30">
+    expires_after="2021-06-30">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
     The result from initializing a D3D11 device in ANGLE. Can be success, or one
     of several error codes which indicate different reasons for failing.
+    Recorded on D3D11 device initialization when ANGLE's D3D backend is in use.
   </summary>
 </histogram>
 
 <histogram name="GPU.ANGLE.D3D9InitializeResult" enum="D3D9InitializeResult"
-    expires_after="M90">
-  <owner>jmadill@chromium.org</owner>
+    expires_after="2021-06-30">
+  <owner>jonahr@google.com</owner>
+  <owner>angle-team@google.com</owner>
   <summary>
     The result from initializing a D3D9 device in ANGLE. Can be success, or one
     of several error codes which indicate different reasons for failing.
+    Recorded on D3D9 device initialization when ANGLE's D3D backend is in use.
   </summary>
 </histogram>
 
-<histogram name="GPU.ANGLE.D3DCompileMS" units="ms" expires_after="2021-02-28">
+<histogram name="GPU.ANGLE.D3DCompileMS" units="ms" expires_after="2021-06-30">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
     The time ANGLE spends calling the D3D shader compiler. Tracks total time we
-    spend compiling shaders on startup and during Chrome's lifetime.
+    spend compiling shaders on startup and during Chrome's lifetime. Recorded on
+    D3D shader compilation when ANGLE's D3D backend is in use.
   </summary>
 </histogram>
 
 <histogram name="GPU.ANGLE.DisplayInitializeMS" units="ms"
-    expires_after="2021-04-04">
+    expires_after="2021-06-30">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
@@ -138,31 +147,35 @@
 </histogram>
 
 <histogram name="GPU.ANGLE.ProgramCache.LoadBinarySuccess"
-    enum="BooleanSuccess" expires_after="2021-06-06">
+    enum="BooleanSuccess" expires_after="2021-06-30">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
-    Records if the call to load a cached binary was successful. This can
-    legitimately fail if the driver wants chrome to re-link and re-cache the gpu
-    program.
+    Records if the call to load a cached binary was successful. Calls are made
+    on shader creation and linking. This can legitimately fail if the driver
+    wants chrome to re-link and re-cache the gpu program.
   </summary>
 </histogram>
 
 <histogram name="GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes" units="bytes"
-    expires_after="M90">
-  <owner>jmadill@chromium.org</owner>
+    expires_after="2021-06-30">
+  <owner>jonahr@google.com</owner>
+  <owner>angle-team@google.com</owner>
   <summary>
-    The size of program binaries loaded into the gpu program cache.
+    Records the size of program binaries loaded into the gpu program cache.
+    Programs are loaded into the cache upon use in draw and dispatch calls.
   </summary>
 </histogram>
 
 <histogram name="GPU.ANGLE.SupportsDXGI1_2" enum="BooleanSupported"
-    expires_after="M90">
-  <owner>jmadill@chromium.org</owner>
+    expires_after="2021-06-30">
+  <owner>jonahr@google.com</owner>
+  <owner>angle-team@google.com</owner>
   <summary>
     Windows computers running Windows 8+, or running Windows 7 with a platform
     update, support the newer version of DXGI. This update also indicates the
     computer is capable of running Direct3D 11.1 if the hardware supports it.
+    Recorded on D3D11 device initialization when ANGLE's D3D backend is in use.
   </summary>
 </histogram>
 
@@ -345,8 +358,9 @@
 </histogram>
 
 <histogram name="GPU.D3DShaderModel" enum="ShaderModel"
-    expires_after="2021-09-01">
-  <owner>jmadill@chromium.org</owner>
+    expires_after="2021-06-30">
+  <owner>jonahr@google.com</owner>
+  <owner>angle-team@google.com</owner>
   <summary>
     ANGLE's currently active D3D shader model version. Logged once every startup
     of the GPU process, on Windows only. Note that Shader Models 2 and 3 map to
@@ -601,7 +615,7 @@
   </summary>
 </histogram>
 
-<histogram name="GPU.DoLinkProgramTime" units="ms" expires_after="2020-11-30">
+<histogram name="GPU.DoLinkProgramTime" units="ms" expires_after="2021-06-30">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
@@ -787,7 +801,7 @@
 </histogram>
 
 <histogram name="GPU.InitializeOneOffMediumTime" units="ms"
-    expires_after="2021-07-04">
+    expires_after="2021-06-30">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
@@ -895,7 +909,7 @@
 </histogram>
 
 <histogram name="GPU.PassthroughDoLinkProgramTime" units="ms"
-    expires_after="2020-11-30">
+    expires_after="2021-06-30">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
@@ -966,7 +980,7 @@
 </histogram>
 
 <histogram name="GPU.ProgramCache.CacheHit" enum="BooleanSuccess"
-    expires_after="2020-11-30">
+    expires_after="2021-06-30">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/login/histograms.xml b/tools/metrics/histograms/histograms_xml/login/histograms.xml
index 9890fcb..602d324 100644
--- a/tools/metrics/histograms/histograms_xml/login/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/login/histograms.xml
@@ -195,7 +195,7 @@
 </histogram>
 
 <histogram name="Login.PromptToCompleteLoginTime" units="ms"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>rsorokin@chromium.org</owner>
   <owner>achuith@chromium.org</owner>
   <owner>cros-oac@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/media/histograms.xml b/tools/metrics/histograms/histograms_xml/media/histograms.xml
index b743ca7e..016be64 100644
--- a/tools/metrics/histograms/histograms_xml/media/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/media/histograms.xml
@@ -1434,7 +1434,7 @@
 </histogram>
 
 <histogram name="Media.EME.CdmFileIO.FileSizeKBOnFirstRead" units="KB"
-    expires_after="2021-05-07">
+    expires_after="2021-07-11">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -1444,7 +1444,7 @@
 </histogram>
 
 <histogram base="true" name="Media.EME.CdmFileIO.TimeTo" units="ms"
-    expires_after="2021-05-07">
+    expires_after="2021-07-11">
   <owner>jrummell@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -1684,7 +1684,7 @@
 </histogram>
 
 <histogram name="Media.EME.OutputProtection" enum="MediaOutputProtectionStatus"
-    expires_after="2021-05-07">
+    expires_after="2021-07-11">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -2993,6 +2993,17 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Remoting.Compatibility" enum="RemotingCompatibility"
+    expires_after="2022-02-01">
+  <owner>takumif@chromium.org</owner>
+  <owner>openscreen-eng@google.com</owner>
+  <summary>
+    Whether the given media is compatible with media remoting. Recorded whenever
+    the conditions are met to start remoting (e.g. the media element is the
+    dominant page content and is not paused).
+  </summary>
+</histogram>
+
 <histogram name="Media.Remoting.SessionDuration" units="ms"
     expires_after="2021-07-01">
   <owner>miu@chromium.org</owner>
@@ -3101,6 +3112,16 @@
   <summary>Video width while remoting content.</summary>
 </histogram>
 
+<histogram name="Media.Remoting.VideoPixelRateSupport"
+    enum="RemotingVideoPixelRateSupport" expires_after="2022-02-01">
+  <owner>takumif@chromium.org</owner>
+  <owner>openscreen-eng@google.com</owner>
+  <summary>
+    Pixels-per-second in a video and whether the receiver supports its playback.
+    Recorded whenever we are about to start media remoting a video.
+  </summary>
+</histogram>
+
 <histogram name="Media.RtcLowLatencyVideoRenderer.AverageQueueLengthX10"
     units="frames" expires_after="2021-05-31">
   <owner>kron@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
index 0ef57b8a..0dee3d6 100644
--- a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
@@ -86,7 +86,7 @@
 </histogram>
 
 <histogram name="MultiDevice.DeviceSyncService.SetSoftwareFeatureState.Result"
-    enum="BooleanSuccess" expires_after="2021-05-09">
+    enum="BooleanSuccess" expires_after="2021-07-11">
   <owner>vecore@google.com</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>Result of enabling and disabling features for devices.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/net/histograms.xml b/tools/metrics/histograms/histograms_xml/net/histograms.xml
index ab499e7..c2dfd7f9 100644
--- a/tools/metrics/histograms/histograms_xml/net/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/net/histograms.xml
@@ -31,7 +31,7 @@
 </histogram>
 
 <histogram name="Net.AlternateProtocolUsage" enum="AlternateProtocolUsage"
-    expires_after="2021-05-11">
+    expires_after="2021-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -1058,7 +1058,7 @@
 </histogram>
 
 <histogram name="Net.DNS.ProbeSequence.ConfigChange.Success.AttemptTime"
-    units="ms" expires_after="2021-04-04">
+    units="ms" expires_after="2021-07-11">
   <owner>ericorth@chromium.org</owner>
   <owner>doh-core@google.com</owner>
   <summary>
@@ -1215,7 +1215,7 @@
 </histogram>
 
 <histogram name="Net.DNS.SecureDnsTask.DnsModeAutomatic.FailureTime" units="ms"
-    expires_after="2021-05-02">
+    expires_after="2021-07-11">
   <owner>ericorth@chromium.org</owner>
   <owner>doh-core@google.com</owner>
   <summary>
@@ -2359,7 +2359,7 @@
 </histogram>
 
 <histogram name="Net.QuicNumSentClientHellos" units="units"
-    expires_after="2021-05-11">
+    expires_after="2021-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>The number of client hello messages sent.</summary>
@@ -2618,7 +2618,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionCloseErrorCodeClient"
-    enum="QuicErrorCodes" expires_after="2021-05-11">
+    enum="QuicErrorCodes" expires_after="2021-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -2638,7 +2638,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionCloseErrorCodeServer"
-    enum="QuicErrorCodes" expires_after="2021-05-11">
+    enum="QuicErrorCodes" expires_after="2021-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3391,7 +3391,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PacketRetransmitsPerMille" units="permille"
-    expires_after="2021-05-11">
+    expires_after="2021-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4442,7 +4442,7 @@
 </histogram>
 
 <histogram name="Net.SpdySession.ClosedOnError" enum="NetErrorCodes"
-    expires_after="2021-05-11">
+    expires_after="2021-07-11">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
index 3f4808b..51848a3 100644
--- a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
@@ -936,7 +936,7 @@
 
 <histogram
     name="NewTabPage.Promo.EnhancedProtectionPromo.ImpressionUntilAction"
-    units="units" expires_after="2021-05-09">
+    units="units" expires_after="2021-07-11">
   <owner>bdea@chromium.org</owner>
   <owner>chrome-safebrowsing-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
index a2870393..21f5a8d5 100644
--- a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
@@ -917,7 +917,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestRequest.Success.GoogleResponseTime" units="ms"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>cch@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 5625c03..549a8c2 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -557,7 +557,7 @@
 </histogram>
 
 <histogram name="AppBanners.DisplayEvent" enum="AppBannersDisplayEvent"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>pjmclachlan@google.com</owner>
   <owner>pcovell@google.com</owner>
   <summary>
@@ -1782,6 +1782,15 @@
   </summary>
 </histogram>
 
+<histogram name="Bookmarks.StarEntryPoint.ClickedAction"
+    enum="StarEntryPointAction" expires_after="M92">
+  <owner>corising@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <summary>
+    Recorded when an action in the Bookmark icon menu is clicked.
+  </summary>
+</histogram>
+
 <histogram name="Bookmarks.UsageCountPerProfileType" enum="BrowserProfileType"
     expires_after="2021-06-01">
   <owner>rhalavati@chromium.org</owner>
@@ -9632,7 +9641,7 @@
 </histogram>
 
 <histogram name="NCN.NetworkOperatorMCCMNC" units="units"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>tbansal@chromium.org</owner>
   <owner>bengr@google.com</owner>
   <summary>
@@ -9732,16 +9741,33 @@
   </token>
 </histogram>
 
+<histogram
+    name="Nearby.Connections.InstantMessaging.{Direction}Express.OAuthTokenFetchResult"
+    enum="BooleanSuccess" expires_after="2021-08-19">
+  <owner>nohle@chromium.org</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
+  <summary>
+    Records whether or not the user was able to fetch the OAuth token necessary
+    to {Direction} the Instant Messaging API. Emitted at the conclusion of the
+    token request, which is attempted right before making HTTPS requests to the
+    Instant Messaging API.
+  </summary>
+  <token key="Direction">
+    <variant name="Receive" summary="start receiving messages from"/>
+    <variant name="Send" summary="send a message to"/>
+  </token>
+</histogram>
+
 <histogram name="Nearby.Connections.InstantMessaging.{Direction}Express.Result"
     enum="BooleanSuccess" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records whether an HTTPS call to {Direction} the Instant Messaging API
     succeeds or fails. Emitted when the HTTPS call succeeds or fails.
   </summary>
   <token key="Direction">
-    <variant name="Receive" summary="receive a message from"/>
+    <variant name="Receive" summary="start receiving messages from"/>
     <variant name="Send" summary="send a message to"/>
   </token>
 </histogram>
@@ -9750,14 +9776,14 @@
     name="Nearby.Connections.InstantMessaging.{Direction}Express.Result.FailureReason"
     enum="CombinedHttpResponseAndNetErrorCode" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the network error code or HTTPS response code from a failed HTTPS
     call to {Direction} the Instant Messaging API. Emitted when the HTTPS call
     fails.
   </summary>
   <token key="Direction">
-    <variant name="Receive" summary="receive a message from"/>
+    <variant name="Receive" summary="start receiving messages from"/>
     <variant name="Send" summary="send a message to"/>
   </token>
 </histogram>
@@ -9766,7 +9792,7 @@
     name="Nearby.Share.Certificates.Manager.BluetoothMacAddressSetInPrivateCertificate"
     enum="BooleanSet" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records whether or not a Bluetooth MAC address is set in the local device's
     private certificate metadata during certificate creation. Emitted when
@@ -9781,7 +9807,7 @@
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesCount"
     units="certificates" expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     If the Nearby Share certificate manager successfully downloads public
     certificates, then record the total number of certificates downloaded across
@@ -9793,7 +9819,7 @@
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesFailuePageCount"
     units="pages" expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     If the Nearby Share certificate manager fails to download public
     certificates, then record the page number of the page on which the failure
@@ -9805,7 +9831,7 @@
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesHttpResult"
     enum="NearbyShareHttpResult" expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the result of the async ListPublicCertificates API call to the
     Nearby Sharing server when the certificate manager periodically downloads
@@ -9818,7 +9844,7 @@
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesSuccessPageCount"
     units="pages" expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     If the Nearby Share certificate manager successfully downloads public
     certificates, then record the number of pages downloaded by the RPC.
@@ -9829,7 +9855,7 @@
     name="Nearby.Share.Certificates.Manager.DownloadPublicCertificatesSuccessRate"
     enum="BooleanSuccess" expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records whether the Nearby Share certificate manager successfully downloaded
     public certificates from the server and stored them in leveldb.
@@ -9841,7 +9867,7 @@
     enum="NearbyShareCertificateManagerGetDecryptedPublicCertificateResult"
     expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the result of the async GetDecryptedPublicCertificate call in
     certificate manager.
@@ -9851,7 +9877,7 @@
 <histogram name="Nearby.Share.Certificates.Storage.InitializeAttemptCount"
     units="attempts" expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     If the Nearby Share certificate storage successfully initializes the public
     certificate database, then record the number of attempts it took.
@@ -9862,7 +9888,7 @@
     enum="NearbyShareCertificateStorageInitializationResult"
     expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     For individual initialization attempts of the Nearby Share certificate
     storage public certificate database, record the init status returned by
@@ -9873,7 +9899,7 @@
 <histogram name="Nearby.Share.Certificates.Storage.{Operation}SuccessRate"
     enum="BooleanSuccess" expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Record success rate of Nearby Share storage operation {Operation}.
   </summary>
@@ -9893,7 +9919,7 @@
 <histogram name="Nearby.Share.Connection.EstablishOutgoingConnectionStatus"
     enum="NearbyShareFinalStatus" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records whether an attempt to establish a connection to a receiving device
     succeeded, failed, or was cancelled. Emitted after the user selects a device
@@ -9906,7 +9932,7 @@
 <histogram name="Nearby.Share.Connection.TimeToEstablishOutgoingConnection"
     units="ms" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the time necessary to successfully establish a connection to a
     receiving device. Emitted after the user selects a device to send a payload
@@ -9920,7 +9946,7 @@
 <histogram name="Nearby.Share.Discovery.Delay.FromStartDiscoveryTo{EndState}"
     units="ms" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the delay between the start of the discovery session and {EndState}.
   </summary>
@@ -9935,7 +9961,7 @@
 <histogram name="Nearby.Share.Discovery.FurthestDiscoveryProgress"
     enum="NearbyShareDiscoveryProgress" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the furthest state reached in a single Nearby Share discovery
     session. Emitted when the per-session discovery manager is destroyed.
@@ -9945,7 +9971,7 @@
 <histogram name="Nearby.Share.Discovery.LookUpSelectedShareTarget"
     enum="BooleanFound" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records whether or not the selected share target on the Nearby Share
     discovery page can be found in the per-session discovery manager's map of
@@ -9957,7 +9983,7 @@
 <histogram name="Nearby.Share.Discovery.NumShareTargets.{Variation}"
     units="share targets" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the number of share targets {Variation} in a single discovery
     session. Emitted once during the discovery session.
@@ -9972,7 +9998,7 @@
 <histogram name="Nearby.Share.Discovery.{Operation}"
     enum="NearbyShareServiceStatusCode" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the result of {Operation}. Emitted immediately after the operation
     is attempted for each discovery session.
@@ -9991,7 +10017,7 @@
 <histogram name="Nearby.Share.Enabled" enum="NearbyShareEnabledState"
     expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records if the user has the Nearby Share feature enabled, and if not,
     records why the feature is not enabled. For example, the feature is not
@@ -10004,7 +10030,7 @@
 <histogram name="Nearby.Share.LocalDeviceData.DeviceDataUpdater.HttpResult"
     enum="NearbyShareHttpResult" expires_after="2021-08-19">
   <owner>cclem@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the result of the async UpdateDevice API call to the Nearby Sharing
     server when the device data updater makes a request. Recorded when the async
@@ -10015,7 +10041,7 @@
 <histogram name="Nearby.Share.Medium.ChangedToMedium"
     enum="NearbyConnectionsMedium" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the data-transfer medium that the Nearby Connections library
     successfully switches to during a Nearby Share transfer. Emitted when the
@@ -10029,7 +10055,7 @@
     Replaced 12/2020 with Nearby.Share.Payload.FinalStatus[...].
   </obsolete>
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records whether a transfer succeeded, failed, or was cancelled when
     transmitted over {UpgradedMedium}. Emitted when the payload transfer
@@ -10046,7 +10072,7 @@
 <histogram name="Nearby.Share.Medium.InitiateBandwidthUpgradeResult"
     enum="BooleanSuccess" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the result of Nearby Share starting a bandwidth upgrade via the
     Nearby Connections library. This metric only records the result of
@@ -10060,7 +10086,7 @@
 <histogram name="Nearby.Share.Medium.RequestedBandwidthUpgradeResult"
     enum="BooleanUpgraded" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records if the transfer medium was successfully upgraded after an explicit
     bandwidth upgrade request from the client. Emitted when the transfer channel
@@ -10071,7 +10097,7 @@
 <histogram name="Nearby.Share.Payload.FinalStatus{UpgradedMedium}"
     enum="NearbyShareFinalStatus" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records whether a payload transfer succeeded, failed, or was cancelled when
     transmitted over {UpgradedMedium}. Emitted when the payload transfer
@@ -10089,7 +10115,7 @@
 <histogram name="Nearby.Share.Payload.NumAttachments{Type}" units="attachments"
     expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the number of {Type} attachments intended to be sent in a Nearby
     Share transfer. Emitted when the transfer concludes, successfully or not.
@@ -10104,7 +10130,7 @@
 <histogram name="Nearby.Share.Payload.TotalSize{Variation}" units="KB"
     expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the total payload size of a Nearby Share transfer {Variation}.
     Emitted when the transfer concludes.
@@ -10135,7 +10161,7 @@
 <histogram name="Nearby.Share.Payload.TransferRate{Variation}" units="KB/s"
     expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the payload transfer rate of a Nearby Share transfer {Variation}.
     Emitted when the transfer concludes.
@@ -10166,7 +10192,7 @@
 <histogram name="Nearby.Share.StartAdvertising.Result.FailureReason{Mode}"
     enum="NearbyShareStartAdvertisingFailureReason" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the reason Nearby Share advertising failed to start in {Mode} mode.
   </summary>
@@ -10180,7 +10206,7 @@
 <histogram name="Nearby.Share.StartAdvertising.Result{Mode}"
     enum="BooleanSuccess" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the result of starting Nearby Share advertising in {Mode} mode.
   </summary>
@@ -10198,7 +10224,7 @@
     Replaced 12/2020 with Nearby.Share.Transfer.FinalStatus[...].
   </obsolete>
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the reason a Nearby Share {Direction} transfer was not completed
     when sharing with {ShareTargetType}. Emitted when a transfer aborts before
@@ -10230,7 +10256,7 @@
     Replaced 12/2020 with Nearby.Share.Transfer.FinalStatus[...].
   </obsolete>
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records if a Nearby Share {Direction} transfer fully completes or not when
     sharing with {ShareTargetType}. Emitted when a transfer completes
@@ -10261,7 +10287,7 @@
 <histogram name="Nearby.Share.Transfer.FinalStatus"
     enum="NearbyShareTransferFinalStatus" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the final status of a Nearby Share transfer. Emitted when a transfer
     completes successfully, fails, or was aborted by the user, for example, by
@@ -10273,7 +10299,7 @@
     name="Nearby.Share.Transfer.FinalStatus.{Direction}.{ShareTargetType}.{ContactStatus}"
     enum="NearbyShareTransferFinalStatus" expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the final status of a Nearby Share {Direction} transfer with
     {ShareTargetType} using {ContactStatus}. Emitted when a transfer completes
@@ -10302,7 +10328,7 @@
     Renamed 12/2020 to Nearby.Share.Payload.NumAttachments[...].
   </obsolete>
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the number of {Type} attachments intended to be sent in a Nearby
     Share transfer. Emitted when the transfer concludes, successfully or not.
@@ -10321,7 +10347,7 @@
     Renamed 12/2020 to Nearby.Share.Payload.TransferRate[...].
   </obsolete>
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the transfer rate of a Nearby Share {Direction} transfer that
     {PayloadStatus} when sharing with {ShareTargetType} over {UpgradedMedium}.
@@ -10361,7 +10387,7 @@
     Renamed 12/2020 to Nearby.Share.Payload.TotalSize[...].
   </obsolete>
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the total payload size of a Nearby Share {Direction} transfer that
     {PayloadStatus} when sharing with {ShareTargetType} over {UpgradedMedium}.
@@ -10397,7 +10423,7 @@
 <histogram name="Nearby.Share.VisibilityChoice" enum="NearbyShareVisibility"
     expires_after="2021-08-19">
   <owner>nohle@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>nearby-share-chromeos-eng@google.com</owner>
   <summary>
     Records the user's chosen degree of visibility to their contacts, selected
     during onboarding or updated in settings. Emitted at login for users that
@@ -11964,7 +11990,7 @@
 </histogram>
 
 <histogram name="Previews.EligibilityReason" enum="PreviewsEligibilityReason"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>ryansturm@chromium.org</owner>
   <summary>
     When evaluating whether to show a user a preview, the preview might be
@@ -13302,7 +13328,7 @@
 </histogram>
 
 <histogram name="SB2.RemoteCall.CanCheckUrl" enum="BooleanCanCheckUrl"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -14328,7 +14354,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.EngagementType"
-    enum="SiteEngagementServiceEngagementType" expires_after="2021-05-09">
+    enum="SiteEngagementServiceEngagementType" expires_after="2021-07-11">
   <owner>calamity@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -14408,7 +14434,7 @@
 </histogram>
 
 <histogram name="SiteIsolatedCodeCache.JS.Behaviour"
-    enum="SiteIsolatedCodeCacheJSBehaviour" expires_after="2021-05-09">
+    enum="SiteIsolatedCodeCacheJSBehaviour" expires_after="2021-07-11">
   <owner>mythria@chromium.org</owner>
   <owner>v8-team@google.com</owner>
   <summary>
@@ -17520,7 +17546,7 @@
 </histogram>
 
 <histogram name="Webapp.InstallResult" enum="WebAppInstallResultCode"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
 <!-- Name completed by histogram_suffixes name="WebAppType" -->
 
   <owner>calamity@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
index 6af3684..cb4e7ac 100644
--- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -127,7 +127,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.BypassedByUser.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -139,7 +139,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.BytesPerSeconds" units="bytes"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -150,7 +150,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -160,7 +160,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.FailedToGetToken.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -171,7 +171,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.FailedToGetVerdict.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -182,7 +182,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.FileEncrypted.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>rogerta@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -193,7 +193,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.FileTooLarge.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -204,7 +204,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.Success.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -214,7 +214,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.Timeout.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -224,7 +224,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.Unknown.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -234,7 +234,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Download.UnsupportedFileType.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -245,7 +245,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.BytesPerSeconds"
-    units="bytes" expires_after="M90">
+    units="bytes" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -257,7 +257,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.CancelledByUser.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -269,7 +269,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -279,7 +279,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.FailedToGetToken.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -290,7 +290,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.FailedToGetVerdict.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -301,7 +301,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.FileEncrypted.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>rogerta@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -312,7 +312,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.FileTooLarge.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -323,7 +323,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.Success.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -334,7 +334,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.Timeout.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -345,7 +345,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.Unknown.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -357,7 +357,7 @@
 
 <histogram
     name="SafeBrowsing.DeepScan.DragAndDrop.UnsupportedFileType.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -368,7 +368,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.BytesPerSeconds" units="bytes"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -379,7 +379,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.CancelledByUser.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -390,7 +390,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -400,7 +400,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.FailedToGetToken.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -411,7 +411,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.FailedToGetVerdict.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -422,7 +422,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.FileTooLarge.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -433,7 +433,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.Success.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -443,7 +443,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.Timeout.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -453,7 +453,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.Unknown.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -463,7 +463,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Paste.UnsupportedFileType.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -474,7 +474,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.BytesPerSeconds" units="bytes"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -485,7 +485,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.CancelledByUser.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -496,7 +496,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -506,7 +506,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.FailedToGetToken.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -517,7 +517,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.FailedToGetVerdict.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -528,7 +528,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.FileEncrypted.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>rogerta@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -539,7 +539,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.FileTooLarge.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -550,7 +550,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.Success.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -560,7 +560,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.Timeout.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -570,7 +570,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.Unknown.Duration" units="ms"
-    expires_after="M90">
+    expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -580,7 +580,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.DeepScan.Upload.UnsupportedFileType.Duration"
-    units="ms" expires_after="M90">
+    units="ms" expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
   <owner>webprotect-team@google.com</owner>
   <summary>
@@ -974,7 +974,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.IsLookupServiceAvailable"
-    enum="BooleanAvailable" expires_after="2021-05-09">
+    enum="BooleanAvailable" expires_after="2021-07-11">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -986,7 +986,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.IsLookupSuccessful" enum="BooleanSuccess"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/service/histograms.xml b/tools/metrics/histograms/histograms_xml/service/histograms.xml
index b3d6db30..4ef4502 100644
--- a/tools/metrics/histograms/histograms_xml/service/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/service/histograms.xml
@@ -423,7 +423,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.InternalsPageAccessed"
-    enum="ServiceWorkerInternalsLinkQuery" expires_after="M90">
+    enum="ServiceWorkerInternalsLinkQuery" expires_after="M94">
   <owner>bashi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1080,7 +1080,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.Storage.DeleteAndStartOverResult"
-    enum="ServiceWorkerDeleteAndStartOverResult" expires_after="M90">
+    enum="ServiceWorkerDeleteAndStartOverResult" expires_after="M94">
   <owner>bashi@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/settings/histograms.xml b/tools/metrics/histograms/histograms_xml/settings/histograms.xml
index 3ac2564..e5028be 100644
--- a/tools/metrics/histograms/histograms_xml/settings/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/settings/histograms.xml
@@ -162,12 +162,12 @@
 </histogram>
 
 <histogram name="Settings.SafetyCheck.ChromeCleanerResult"
-    enum="SafetyCheckChromeCleanerStatus" expires_after="M90">
+    enum="SafetyCheckChromeCleanerStatus" expires_after="M92">
   <owner>rainhard@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <summary>
-    Resulting state of the safety check Chrome cleaner check. Value 4-9 got
-    added with M88.
+    Resulting state of the safety check Chrome cleaner check. Recorded when a
+    safety check is run by the user. Value 4-9 got added with M88.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/histograms_xml/stability/histograms.xml b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
index 666cac41..ee1cd40 100644
--- a/tools/metrics/histograms/histograms_xml/stability/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
@@ -46,7 +46,7 @@
 </histogram>
 
 <histogram name="Stability.Android.ProcessedCrashCounts"
-    enum="AndroidProcessedCrashCounts" expires_after="2021-05-09">
+    enum="AndroidProcessedCrashCounts" expires_after="2021-07-11">
   <owner>boliu@chromium.org</owner>
   <summary>
     Individual enum counts specific conditions of child process terminations.
@@ -131,7 +131,7 @@
 </histogram>
 
 <histogram name="Stability.BadMessageTerminated.Content"
-    enum="BadMessageReasonContent" expires_after="2021-05-09">
+    enum="BadMessageReasonContent" expires_after="2021-07-11">
   <owner>jam@chromium.org</owner>
   <owner>jamescook@chromium.org</owner>
   <summary>
@@ -261,7 +261,7 @@
 </histogram>
 
 <histogram name="Stability.Experimental.PageLoads" enum="StabilityPageLoadType"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>fdoray@chromium.org</owner>
   <owner>chrome-catan@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/startup/histograms.xml b/tools/metrics/histograms/histograms_xml/startup/histograms.xml
index e55f8e3b..78c4035 100644
--- a/tools/metrics/histograms/histograms_xml/startup/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/startup/histograms.xml
@@ -56,7 +56,7 @@
 </histogram>
 
 <histogram base="true" name="Startup.Android.Cold.TimeToFirstContentfulPaint"
-    units="ms" expires_after="2021-05-09">
+    units="ms" expires_after="2021-07-11">
   <owner>pasko@chromium.org</owner>
   <owner>alexilin@chromium.org</owner>
   <summary>
@@ -69,7 +69,7 @@
 </histogram>
 
 <histogram base="true" name="Startup.Android.Cold.TimeToFirstNavigationCommit"
-    units="ms" expires_after="2021-05-09">
+    units="ms" expires_after="2021-07-11">
   <owner>pasko@chromium.org</owner>
   <owner>alexilin@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
index 893de4e..4990171 100644
--- a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
@@ -421,7 +421,7 @@
 </histogram>
 
 <histogram name="SubresourceFilter.PageLoad.ActivationList"
-    enum="ActivationList" expires_after="2021-05-09">
+    enum="ActivationList" expires_after="2021-07-11">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
@@ -431,7 +431,7 @@
 </histogram>
 
 <histogram name="SubresourceFilter.PageLoad.ActivationState"
-    enum="SubresourceFilterActivationState" expires_after="2021-05-09">
+    enum="SubresourceFilterActivationState" expires_after="2021-07-11">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sync/histograms.xml b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
index f127f70..99cc772 100644
--- a/tools/metrics/histograms/histograms_xml/sync/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
@@ -802,7 +802,7 @@
 </histogram>
 
 <histogram name="Sync.PostedDataTypeCommitRequest" enum="SyncModelTypes"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>mastiz@chromium.org</owner>
   <owner>jkrcal@chromium.org</owner>
   <summary>
@@ -815,7 +815,7 @@
 </histogram>
 
 <histogram name="Sync.PostedDataTypeGetUpdatesRequest" enum="SyncModelTypes"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>mastiz@chromium.org</owner>
   <owner>jkrcal@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/uma/histograms.xml b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
index 7a01bb06..46b4f97 100644
--- a/tools/metrics/histograms/histograms_xml/uma/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
@@ -225,7 +225,7 @@
 </histogram>
 
 <histogram name="UMA.LogUpload.Canceled.CellularConstraint"
-    enum="BooleanCanceled" expires_after="2021-05-09">
+    enum="BooleanCanceled" expires_after="2021-07-11">
   <owner>holte@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
diff --git a/tools/metrics/histograms/histograms_xml/v8/histograms.xml b/tools/metrics/histograms/histograms_xml/v8/histograms.xml
index 5a21d97..8c4b94b 100644
--- a/tools/metrics/histograms/histograms_xml/v8/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/v8/histograms.xml
@@ -355,7 +355,7 @@
   </summary>
 </histogram>
 
-<histogram name="V8.Execute" units="ms" expires_after="2021-05-09">
+<histogram name="V8.Execute" units="ms" expires_after="2021-07-11">
   <owner>rmcilroy@chromium.org</owner>
   <summary>
     Time spent in JavaScript Execution, including runtime calls, callbacks, and
@@ -841,7 +841,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeExecute" units="microseconds"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -853,7 +853,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeFinalize" units="microseconds"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -865,7 +865,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeForOnStackReplacementExecute"
-    units="microseconds" expires_after="2021-05-09">
+    units="microseconds" expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -878,7 +878,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeForOnStackReplacementFinalize"
-    units="microseconds" expires_after="2021-05-09">
+    units="microseconds" expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -891,7 +891,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeForOnStackReplacementPrepare"
-    units="microseconds" expires_after="2021-05-09">
+    units="microseconds" expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -904,7 +904,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeForOnStackReplacementTotalTime"
-    units="microseconds" expires_after="2021-05-09">
+    units="microseconds" expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -930,7 +930,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizePrepare" units="microseconds"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -942,7 +942,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeTotalBackground" units="microseconds"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -954,7 +954,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeTotalForeground" units="microseconds"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -966,7 +966,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeTotalTime" units="microseconds"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
index faeea7494..50da81e 100644
--- a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
@@ -406,7 +406,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.DelayedPacketOutageEventMs" units="ms"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>hlundin@chromium.org</owner>
   <summary>
     Measures the duration of each packet loss concealment (a.k.a. expand) event
@@ -730,7 +730,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.ExpandRatePercent" units="%"
-    expires_after="2021-05-09">
+    expires_after="2021-07-11">
   <owner>hlundin@chromium.org</owner>
   <summary>
     Measures the expand rate for an incoming WebRTC audio stream. The expand
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 74eb1c5..0d357a4 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -2,15 +2,15 @@
     "trace_processor_shell": {
         "win": {
             "hash": "f3800b3c8e2857a159879265b67126c6ab2495e7",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/53a231c0ae868366179bd560b68a2f5f4b166541/trace_processor_shell.exe"
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/e3e59aac750e507e91be98ff4944a7bdd601a08e/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "fd0d9f70fe09c168bbb999ade77e6f9e4c991c3c",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/53a231c0ae868366179bd560b68a2f5f4b166541/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/bd6bd346f6773bdded75a794f6af704018722de4/trace_processor_shell"
         },
         "linux": {
             "hash": "9de25afa2969d17640815fe3b83e4427b0526564",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/53a231c0ae868366179bd560b68a2f5f4b166541/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/e3e59aac750e507e91be98ff4944a7bdd601a08e/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/page_sets/data/tab_search_desktop.json b/tools/perf/page_sets/data/tab_search_desktop.json
index e6cb1de7..df18140 100644
--- a/tools/perf/page_sets/data/tab_search_desktop.json
+++ b/tools/perf/page_sets/data/tab_search_desktop.json
@@ -1,11 +1,20 @@
 {
     "archives": {
+        "tab_search:clean_slate": {
+            "DEFAULT": "tab_search_desktop_1b410a96cc.wprgo"
+        },
         "tab_search:close_and_open:2020": {
             "DEFAULT": "tab_search_desktop_1b410a96cc.wprgo"
         },
         "tab_search:close_and_open:loading:2020": {
             "DEFAULT": "tab_search_desktop_5284f907bd.wprgo"
         },
+        "tab_search:measure_memory:after": {
+            "DEFAULT": "tab_search_desktop_1b410a96cc.wprgo"
+        },
+        "tab_search:measure_memory:before": {
+            "DEFAULT": "tab_search_desktop_1b410a96cc.wprgo"
+        },
         "tab_search:scroll_up_and_down:2020": {
             "DEFAULT": "tab_search_desktop_0c9707c535.wprgo"
         },
diff --git a/tools/perf/page_sets/tab_search/tab_search_stories.py b/tools/perf/page_sets/tab_search/tab_search_stories.py
index 3807211..aa87b5f1 100644
--- a/tools/perf/page_sets/tab_search/tab_search_stories.py
+++ b/tools/perf/page_sets/tab_search/tab_search_stories.py
@@ -17,6 +17,9 @@
       tab_search_story.TabSearchStoryCloseAndOpen,
       tab_search_story.TabSearchStoryCloseAndOpenLoading,
       tab_search_story.TabSearchStoryScrollUpAndDown,
+      tab_search_story.TabSearchStoryCleanSlate,
+      tab_search_story.TabSearchStoryMeasureMemoryBefore,
+      tab_search_story.TabSearchStoryMeasureMemoryAfter,
   ]
 
   def __init__(self):
diff --git a/tools/perf/page_sets/tab_search/tab_search_story.py b/tools/perf/page_sets/tab_search/tab_search_story.py
index 57759ffc..baa7519 100644
--- a/tools/perf/page_sets/tab_search/tab_search_story.py
+++ b/tools/perf/page_sets/tab_search/tab_search_story.py
@@ -75,7 +75,8 @@
   def RunNavigateSteps(self, action_runner):
     url_list = self.URL_LIST
     tabs = action_runner.tab.browser.tabs
-    tabs[0].Navigate('https://' + url_list[0])
+    if len(url_list) > 0:
+      tabs[0].Navigate('https://' + url_list[0])
     for url in url_list[1:]:
       new_tab = tabs.New()
       new_tab.Navigate('https://' + url)
@@ -255,6 +256,50 @@
     self.ScrollUpAndDown(action_runner)
 
 
+class TabSearchStoryCleanSlate(TabSearchStory):
+  NAME = 'tab_search:clean_slate'
+  URL_LIST = []
+  URL = 'about:blank'
+  WAIT_FOR_NETWORK_QUIESCENCE = False
+
+  def InteractWithPage(self, action_runner):
+    action_runner.Wait(1)
+
+
+class TabSearchStoryMeasureMemory(TabSearchStory):
+  URL_LIST = []
+  URL = 'about:blank'
+  WAIT_FOR_NETWORK_QUIESCENCE = False
+
+  def WillStartTracing(self, chrome_trace_config):
+    chrome_trace_config.category_filter.AddExcludedCategory('*')
+    chrome_trace_config.category_filter.AddIncludedCategory('blink.console')
+    chrome_trace_config.category_filter.AddDisabledByDefault(
+        'disabled-by-default-memory-infra')
+
+  def GetExtraTracingMetrics(self):
+    return ['memoryMetric']
+
+
+class TabSearchStoryMeasureMemoryBefore(TabSearchStoryMeasureMemory):
+  NAME = 'tab_search:measure_memory:before'
+
+  def RunNavigateSteps(self, action_runner):
+    super(TabSearchStoryMeasureMemoryBefore,
+          self).RunNavigateSteps(action_runner)
+    action_runner.MeasureMemory(deterministic_mode=True)
+
+  def InteractWithPage(self, action_runner):
+    action_runner.Wait(1)
+
+
+class TabSearchStoryMeasureMemoryAfter(TabSearchStoryMeasureMemory):
+  NAME = 'tab_search:measure_memory:after'
+
+  def InteractWithPage(self, action_runner):
+    action_runner.MeasureMemory(deterministic_mode=True)
+
+
 SCROLL_ELEMENT_FUNCTION = '''
 document.querySelector('tab-search-app').shadowRoot.getElementById('tabsList')
 '''
diff --git a/ui/accessibility/extensions/chromevoxclassic/BUILD.gn b/ui/accessibility/extensions/chromevoxclassic/BUILD.gn
index 6820dca..0af3f537 100644
--- a/ui/accessibility/extensions/chromevoxclassic/BUILD.gn
+++ b/ui/accessibility/extensions/chromevoxclassic/BUILD.gn
@@ -535,7 +535,7 @@
     "//chrome/test:test_support_ui",
     "//chrome/test/data:web_ui_test_bindings",
     "//chromeos/constants:constants",
-    "//components/webapps",
+    "//components/webapps/browser",
     "//content/test:test_support",
     "//extensions/browser:test_support",
     "//testing/gmock",
diff --git a/ui/base/ime/chromeos/ime_input_context_handler_interface.h b/ui/base/ime/chromeos/ime_input_context_handler_interface.h
index 0fd0f092..ce021fe 100644
--- a/ui/base/ime/chromeos/ime_input_context_handler_interface.h
+++ b/ui/base/ime/chromeos/ime_input_context_handler_interface.h
@@ -11,6 +11,7 @@
 #include "base/component_export.h"
 #include "ui/base/ime/composition_text.h"
 #include "ui/base/ime/input_method.h"
+#include "ui/base/ime/text_input_client.h"
 #include "ui/events/event.h"
 
 namespace ui {
@@ -23,7 +24,9 @@
 class COMPONENT_EXPORT(UI_BASE_IME_CHROMEOS) IMEInputContextHandlerInterface {
  public:
   // Called when the engine commit a text.
-  virtual void CommitText(const std::string& text) = 0;
+  virtual void CommitText(
+      const std::string& text,
+      TextInputClient::InsertTextCursorBehavior cursor_behavior) = 0;
 
   // Called when the engine changes the composition range.
   // Returns true if the operation was successful.
diff --git a/ui/base/ime/chromeos/input_method_chromeos.cc b/ui/base/ime/chromeos/input_method_chromeos.cc
index 9bc9912..66da282 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos.cc
@@ -442,6 +442,7 @@
 
   pending_composition_ = base::nullopt;
   result_text_.clear();
+  result_text_cursor_ = 0;
   composing_text_ = false;
   composition_changed_ = false;
 
@@ -578,9 +579,22 @@
         client->InsertChar(ch_event);
       }
     } else {
-      client->InsertText(
-          result_text_,
-          TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+      // Split |result_text_| into two separate commits, one for the substring
+      // before |result_text_cursor_| and one for the substring after.
+      const base::string16 before_cursor =
+          result_text_.substr(0, result_text_cursor_);
+      if (!before_cursor.empty()) {
+        client->InsertText(
+            before_cursor,
+            TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+      }
+      const base::string16 after_cursor =
+          result_text_.substr(result_text_cursor_);
+      if (!after_cursor.empty()) {
+        client->InsertText(
+            after_cursor,
+            TextInputClient::InsertTextCursorBehavior::kMoveCursorBeforeText);
+      }
       composing_text_ = false;
     }
   }
@@ -612,16 +626,24 @@
   // We should not clear composition text here, as it may belong to the next
   // composition session.
   result_text_.clear();
+  result_text_cursor_ = 0;
   composition_changed_ = false;
 }
 
 bool InputMethodChromeOS::NeedInsertChar() const {
   return GetTextInputClient() &&
-      (IsTextInputTypeNone() ||
-       (!composing_text_ && result_text_.length() == 1));
+         (IsTextInputTypeNone() ||
+          (!composing_text_ && result_text_.length() == 1 &&
+           result_text_cursor_ == 1));
 }
 
-void InputMethodChromeOS::CommitText(const std::string& text) {
+bool InputMethodChromeOS::HasInputMethodResult() const {
+  return result_text_.length() || composition_changed_;
+}
+
+void InputMethodChromeOS::CommitText(
+    const std::string& text,
+    TextInputClient::InsertTextCursorBehavior cursor_behavior) {
   if (text.empty())
     return;
 
@@ -642,7 +664,11 @@
 
   // Append the text to the buffer, because commit signal might be fired
   // multiple times when processing a key event.
-  result_text_.append(utf16_text);
+  result_text_.insert(result_text_cursor_, utf16_text);
+  if (cursor_behavior ==
+      TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText) {
+    result_text_cursor_ += utf16_text.length();
+  }
 
   // If we are not handling key event, do not bother sending text result if the
   // focused text input client does not support text input.
@@ -653,6 +679,7 @@
           TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
     SendFakeProcessKeyEvent(false);
     result_text_.clear();
+    result_text_cursor_ = 0;
   }
 }
 
@@ -763,7 +790,8 @@
   std::string commit_text =
       base::UTF16ToUTF8(character_composer_.composed_character());
   if (!commit_text.empty()) {
-    CommitText(commit_text);
+    CommitText(commit_text,
+               TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   }
   return true;
 }
diff --git a/ui/base/ime/chromeos/input_method_chromeos.h b/ui/base/ime/chromeos/input_method_chromeos.h
index 2805383..f2987b2 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.h
+++ b/ui/base/ime/chromeos/input_method_chromeos.h
@@ -53,7 +53,9 @@
                                 TextInputClient* focused) override;
 
   // ui::IMEInputContextHandlerInterface overrides:
-  void CommitText(const std::string& text) override;
+  void CommitText(
+      const std::string& text,
+      TextInputClient::InsertTextCursorBehavior cursor_behavior) override;
   bool SetCompositionRange(
       uint32_t before,
       uint32_t after,
@@ -158,6 +160,10 @@
   // processing result of the pending key event.
   base::string16 result_text_;
 
+  // Where the cursor should be place after inserting |result_text_|.
+  // 0 <= |result_text_cursor_| <= |result_text_.length()|.
+  size_t result_text_cursor_ = 0;
+
   base::string16 previous_surrounding_text_;
   gfx::Range previous_selection_range_;
 
diff --git a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
index 4bf8a8d..048d03a 100644
--- a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
@@ -89,8 +89,10 @@
     }
     return details;
   }
-  void CommitText(const std::string& text) override {
-    InputMethodChromeOS::CommitText(text);
+  void CommitText(
+      const std::string& text,
+      TextInputClient::InsertTextCursorBehavior cursor_behavior) override {
+    InputMethodChromeOS::CommitText(text, cursor_behavior);
     text_committed_ = text;
   }
 
@@ -447,7 +449,8 @@
        OnWillChangeFocusedClientClearAutocorrectRange) {
   input_type_ = TEXT_INPUT_TYPE_TEXT;
   ime_->SetFocusedTextInputClient(this);
-  ime_->CommitText("hello");
+  ime_->CommitText(
+      "hello", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   ime_->SetAutocorrectRange(gfx::Range(0, 5));
   EXPECT_EQ(gfx::Range(0, 5), this->GetAutocorrectRange());
 
@@ -1018,7 +1021,9 @@
   EXPECT_EQ(kFlags, key_event->flags());
   EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count());
 
-  static_cast<IMEInputContextHandlerInterface*>(ime_.get())->CommitText("A");
+  static_cast<IMEInputContextHandlerInterface*>(ime_.get())
+      ->CommitText(
+          "A", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
 
   EXPECT_EQ(0, inserted_char_);
 
@@ -1178,7 +1183,8 @@
 TEST_F(InputMethodChromeOSKeyEventTest, SetAutocorrectRangeRunsAfterKeyEvent) {
   input_type_ = TEXT_INPUT_TYPE_TEXT;
   ime_->OnTextInputTypeChanged(this);
-  ime_->CommitText("a");
+  ime_->CommitText(
+      "a", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
 
   ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
   ime_->DispatchKeyEvent(&event);
@@ -1196,7 +1202,8 @@
   ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
   ime_->DispatchKeyEvent(&event);
 
-  ime_->CommitText("a");
+  ime_->CommitText(
+      "a", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   ime_->SetAutocorrectRange(gfx::Range(0, 1));
   std::move(mock_ime_engine_handler_->last_passed_callback())
       .Run(/*handled=*/true);
@@ -1205,4 +1212,50 @@
   EXPECT_EQ(gfx::Range(0, 1), GetAutocorrectRange());
 }
 
+TEST_F(InputMethodChromeOSKeyEventTest,
+       MultipleCommitTextsWhileHandlingKeyEventCoalescesIntoOne) {
+  FakeTextInputClient fake_text_input_client(TEXT_INPUT_TYPE_TEXT);
+  InputMethodChromeOS ime(this);
+  ime.SetFocusedTextInputClient(&fake_text_input_client);
+
+  ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
+  ime.DispatchKeyEvent(&event);
+  ime.CommitText(
+      "a", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+  ime.CommitText(
+      "b", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+  ime.CommitText(
+      "cde", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+  std::move(mock_ime_engine_handler_->last_passed_callback())
+      .Run(/*handled=*/true);
+
+  EXPECT_EQ(fake_text_input_client.text(), base::ASCIIToUTF16("abcde"));
+  EXPECT_EQ(fake_text_input_client.selection(), gfx::Range(5, 5));
+}
+
+TEST_F(InputMethodChromeOSKeyEventTest,
+       MultipleCommitTextsWhileHandlingKeyEventCoalescesByCaretBehavior) {
+  FakeTextInputClient fake_text_input_client(TEXT_INPUT_TYPE_TEXT);
+  InputMethodChromeOS ime(this);
+  ime.SetFocusedTextInputClient(&fake_text_input_client);
+
+  ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
+  ime.DispatchKeyEvent(&event);
+  ime.CommitText(
+      "a", TextInputClient::InsertTextCursorBehavior::kMoveCursorBeforeText);
+  ime.CommitText(
+      "b", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+  ime.CommitText(
+      "c", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+  ime.CommitText(
+      "d", TextInputClient::InsertTextCursorBehavior::kMoveCursorBeforeText);
+  ime.CommitText(
+      "e", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+  std::move(mock_ime_engine_handler_->last_passed_callback())
+      .Run(/*handled=*/true);
+
+  EXPECT_EQ(fake_text_input_client.text(), base::ASCIIToUTF16("bceda"));
+  EXPECT_EQ(fake_text_input_client.selection(), gfx::Range(3, 3));
+}
+
 }  // namespace ui
diff --git a/ui/base/ime/chromeos/mock_ime_input_context_handler.cc b/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
index 41f39c6e8..97980f59 100644
--- a/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
+++ b/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
@@ -21,7 +21,9 @@
 
 MockIMEInputContextHandler::~MockIMEInputContextHandler() = default;
 
-void MockIMEInputContextHandler::CommitText(const std::string& text) {
+void MockIMEInputContextHandler::CommitText(
+    const std::string& text,
+    TextInputClient::InsertTextCursorBehavior cursor_behavior) {
   ++commit_text_call_count_;
   last_commit_text_ = text;
 }
@@ -115,7 +117,8 @@
     return;
 
   CommitText(
-      base::UTF16ToUTF8(last_update_composition_arg_.composition_text.text));
+      base::UTF16ToUTF8(last_update_composition_arg_.composition_text.text),
+      TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   last_update_composition_arg_.composition_text.text = base::string16();
 }
 
diff --git a/ui/base/ime/chromeos/mock_ime_input_context_handler.h b/ui/base/ime/chromeos/mock_ime_input_context_handler.h
index e4dcda2..29c76f2 100644
--- a/ui/base/ime/chromeos/mock_ime_input_context_handler.h
+++ b/ui/base/ime/chromeos/mock_ime_input_context_handler.h
@@ -33,7 +33,9 @@
   MockIMEInputContextHandler();
   virtual ~MockIMEInputContextHandler();
 
-  void CommitText(const std::string& text) override;
+  void CommitText(
+      const std::string& text,
+      TextInputClient::InsertTextCursorBehavior cursor_behavior) override;
   void UpdateCompositionText(const CompositionText& text,
                              uint32_t cursor_pos,
                              bool visible) override;
diff --git a/ui/base/ime/fake_text_input_client.cc b/ui/base/ime/fake_text_input_client.cc
index 54a4266..262234b 100644
--- a/ui/base/ime/fake_text_input_client.cc
+++ b/ui/base/ime/fake_text_input_client.cc
@@ -30,7 +30,15 @@
 
 void FakeTextInputClient::InsertText(
     const base::string16& text,
-    TextInputClient::InsertTextCursorBehavior cursor_behavior) {}
+    TextInputClient::InsertTextCursorBehavior cursor_behavior) {
+  text_.insert(selection_.start(), text);
+
+  if (cursor_behavior ==
+      TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText) {
+    selection_ = gfx::Range(selection_.start() + text.length(),
+                            selection_.end() + text.length());
+  }
+}
 
 void FakeTextInputClient::InsertChar(const KeyEvent& event) {}
 
diff --git a/ui/base/ime/fake_text_input_client.h b/ui/base/ime/fake_text_input_client.h
index 284b688..e22d14fc 100644
--- a/ui/base/ime/fake_text_input_client.h
+++ b/ui/base/ime/fake_text_input_client.h
@@ -25,6 +25,8 @@
   ~FakeTextInputClient() override;
 
   void set_text_input_type(TextInputType text_input_type);
+  const base::string16& text() const { return text_; }
+  const gfx::Range& selection() const { return selection_; }
 
   // TextInputClient:
   void SetCompositionText(const CompositionText& composition) override;
@@ -82,6 +84,8 @@
 
  private:
   TextInputType text_input_type_;
+  base::string16 text_;
+  gfx::Range selection_;
 };
 
 }  // namespace ui
diff --git a/ui/gl/yuv_to_rgb_converter.cc b/ui/gl/yuv_to_rgb_converter.cc
index 514290e..e6be831 100644
--- a/ui/gl/yuv_to_rgb_converter.cc
+++ b/ui/gl/yuv_to_rgb_converter.cc
@@ -195,6 +195,10 @@
       g_current_gl_driver->ext.b_GL_ANGLE_get_tex_level_parameter;
   has_robust_resource_init_ =
       g_current_gl_driver->ext.b_GL_ANGLE_robust_resource_initialization;
+
+  has_sampler_objects_ = gl_version_info.IsAtLeastGLES(3, 0) ||
+                         gl_version_info.IsAtLeastGL(3, 3) ||
+                         g_current_gl_driver->ext.b_GL_ARB_sampler_objects;
 }
 
 YUVToRGBConverter::~YUVToRGBConverter() {
@@ -233,9 +237,19 @@
   GLint old_texture0_binding = -1;
   glActiveTexture(GL_TEXTURE0);
   glGetIntegerv(source_target_getter, &old_texture0_binding);
+  GLint old_sampler0_binding = -1;
+  if (has_sampler_objects_) {
+    glGetIntegerv(GL_SAMPLER_BINDING, &old_sampler0_binding);
+    glBindSampler(0, 0);
+  }
   GLint old_texture1_binding = -1;
   glActiveTexture(GL_TEXTURE1);
   glGetIntegerv(source_target_getter, &old_texture1_binding);
+  GLint old_sampler1_binding = -1;
+  if (has_sampler_objects_) {
+    glGetIntegerv(GL_SAMPLER_BINDING, &old_sampler1_binding);
+    glBindSampler(1, 0);
+  }
 
   // Allocate the rgb texture.
   glActiveTexture(old_active_texture);
@@ -312,6 +326,10 @@
   glActiveTexture(GL_TEXTURE1);
   glBindTexture(source_texture_target_, old_texture1_binding);
   glActiveTexture(old_active_texture);
+  if (old_sampler0_binding > 0)
+    glBindSampler(0, old_sampler0_binding);
+  if (old_sampler1_binding > 0)
+    glBindSampler(1, old_sampler1_binding);
 }
 
 }  // namespace gl
diff --git a/ui/gl/yuv_to_rgb_converter.h b/ui/gl/yuv_to_rgb_converter.h
index 28d47d444..9be78a0 100644
--- a/ui/gl/yuv_to_rgb_converter.h
+++ b/ui/gl/yuv_to_rgb_converter.h
@@ -44,6 +44,7 @@
   unsigned source_texture_target_ = 0;
   bool has_get_tex_level_parameter_ = false;
   bool has_robust_resource_init_ = false;
+  bool has_sampler_objects_ = false;
 };
 
 }  // namespace gl
diff --git a/ui/native_theme/native_theme_android.cc b/ui/native_theme/native_theme_android.cc
index 509c9d2..6ec3d28 100644
--- a/ui/native_theme/native_theme_android.cc
+++ b/ui/native_theme/native_theme_android.cc
@@ -55,6 +55,90 @@
                 static_cast<int>(rect->bottom()) - 1);
 }
 
+SkColor NativeThemeAndroid::ControlsAccentColorForState(
+    State state,
+    ColorScheme color_scheme) const {
+  ControlColorId color_id;
+  if (state == kPressed) {
+    color_id = kPressedAccent;
+  } else if (state == kDisabled) {
+    color_id = kDisabledAccent;
+  } else {
+    color_id = kAccent;
+  }
+  return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ControlsSliderColorForState(
+    State state,
+    ColorScheme color_scheme) const {
+  ControlColorId color_id;
+  if (state == kPressed) {
+    color_id = kPressedSlider;
+  } else if (state == kDisabled) {
+    color_id = kDisabledSlider;
+  } else {
+    color_id = kSlider;
+  }
+  return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ControlsBorderColorForState(
+    State state,
+    ColorScheme color_scheme) const {
+  ControlColorId color_id;
+  if (state == kPressed) {
+    color_id = kPressedBorder;
+  } else if (state == kDisabled) {
+    color_id = kDisabledBorder;
+  } else {
+    color_id = kBorder;
+  }
+  return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ButtonBorderColorForState(
+    State state,
+    ColorScheme color_scheme) const {
+  ControlColorId color_id;
+  if (state == kPressed) {
+    color_id = kButtonPressedBorder;
+  } else if (state == kDisabled) {
+    color_id = kButtonDisabledBorder;
+  } else {
+    color_id = kButtonBorder;
+  }
+  return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ControlsFillColorForState(
+    State state,
+    ColorScheme color_scheme) const {
+  ControlColorId color_id;
+  if (state == kPressed) {
+    color_id = kPressedFill;
+  } else if (state == kDisabled) {
+    color_id = kDisabledFill;
+  } else {
+    color_id = kFill;
+  }
+  return GetControlColor(color_id, color_scheme);
+}
+
+SkColor NativeThemeAndroid::ButtonFillColorForState(
+    State state,
+    ColorScheme color_scheme) const {
+  ControlColorId color_id;
+  if (state == kPressed) {
+    color_id = kButtonPressedFill;
+  } else if (state == kDisabled) {
+    color_id = kButtonDisabledFill;
+  } else {
+    color_id = kButtonFill;
+  }
+  return GetControlColor(color_id, color_scheme);
+}
+
 NativeThemeAndroid::NativeThemeAndroid() {
 }
 
diff --git a/ui/native_theme/native_theme_android.h b/ui/native_theme/native_theme_android.h
index 6d5c381..6d34555c 100644
--- a/ui/native_theme/native_theme_android.h
+++ b/ui/native_theme/native_theme_android.h
@@ -28,6 +28,20 @@
 
   // NativeThemeBase:
   void AdjustCheckboxRadioRectForPadding(SkRect* rect) const override;
+  // TODO(crbug.com/1165342): Refine hover state behavior on available pointing
+  // devices.
+  SkColor ControlsAccentColorForState(State state,
+                                      ColorScheme color_scheme) const override;
+  SkColor ControlsSliderColorForState(State state,
+                                      ColorScheme color_scheme) const override;
+  SkColor ButtonBorderColorForState(State state,
+                                    ColorScheme color_scheme) const override;
+  SkColor ButtonFillColorForState(State state,
+                                  ColorScheme color_scheme) const override;
+  SkColor ControlsBorderColorForState(State state,
+                                      ColorScheme color_scheme) const override;
+  SkColor ControlsFillColorForState(State state,
+                                    ColorScheme color_scheme) const override;
 
  private:
   NativeThemeAndroid();
diff --git a/ui/native_theme/native_theme_base.h b/ui/native_theme/native_theme_base.h
index c4e206b..3c2c17b 100644
--- a/ui/native_theme/native_theme_base.h
+++ b/ui/native_theme/native_theme_base.h
@@ -234,6 +234,18 @@
   SkColor GetArrowColor(State state, ColorScheme color_scheme) const;
   SkColor GetControlColor(ControlColorId color_id,
                           ColorScheme color_scheme) const;
+  virtual SkColor ControlsAccentColorForState(State state,
+                                              ColorScheme color_scheme) const;
+  virtual SkColor ControlsSliderColorForState(State state,
+                                              ColorScheme color_scheme) const;
+  virtual SkColor ButtonBorderColorForState(State state,
+                                            ColorScheme color_scheme) const;
+  virtual SkColor ButtonFillColorForState(State state,
+                                          ColorScheme color_scheme) const;
+  virtual SkColor ControlsBorderColorForState(State state,
+                                              ColorScheme color_scheme) const;
+  virtual SkColor ControlsFillColorForState(State state,
+                                            ColorScheme color_scheme) const;
 
   int scrollbar_width_ = 15;
 
@@ -268,19 +280,8 @@
                                   const SkScalar border_radius,
                                   ColorScheme color_scheme) const;
 
-  SkColor ButtonBorderColorForState(State state,
-                                    ColorScheme color_scheme) const;
-  SkColor ButtonFillColorForState(State state, ColorScheme color_scheme) const;
-  SkColor ControlsAccentColorForState(State state,
-                                      ColorScheme color_scheme) const;
-  SkColor ControlsBorderColorForState(State state,
-                                      ColorScheme color_scheme) const;
-  SkColor ControlsFillColorForState(State state,
-                                    ColorScheme color_scheme) const;
   SkColor ControlsBackgroundColorForState(State state,
                                           ColorScheme color_scheme) const;
-  SkColor ControlsSliderColorForState(State state,
-                                      ColorScheme color_scheme) const;
   SkColor GetHighContrastControlColor(ControlColorId color_id,
                                       ColorScheme color_scheme) const;
   SkColor GetDarkModeControlColor(ControlColorId color_id) const;
diff --git a/ui/views/layout/layout_manager.h b/ui/views/layout/layout_manager.h
index 22a3a60..494f6769 100644
--- a/ui/views/layout/layout_manager.h
+++ b/ui/views/layout/layout_manager.h
@@ -67,7 +67,11 @@
   virtual int GetPreferredHeightForWidth(const View* host, int width) const;
 
   // Returns the maximum space available in the layout for the specified child
-  // view. Default is unbounded.
+  // view. Default is unbounded. May result in a layout calculation for |host|
+  // if the layout is not valid, so while it can be called during the Layout()
+  // method for |view|, it should never be called during the actual computation
+  // of |host|'s layout (e.g. in a FlexLayout FlexRule calculation) to prevent
+  // an infinite loop.
   virtual SizeBounds GetAvailableSize(const View* host, const View* view) const;
 
   // Called when a View is added as a child of the View the LayoutManager has
diff --git a/ui/views/layout/layout_manager_base.cc b/ui/views/layout/layout_manager_base.cc
index 68f1874..4541528 100644
--- a/ui/views/layout/layout_manager_base.cc
+++ b/ui/views/layout/layout_manager_base.cc
@@ -63,6 +63,8 @@
 SizeBounds LayoutManagerBase::GetAvailableSize(const View* host,
                                                const View* view) const {
   DCHECK_EQ(host_view_, host);
+  if (!cached_layout_size_)
+    GetProposedLayout(host->size());
   if (cached_layout_size_) {
     for (const auto& child_layout : cached_layout_.child_layouts)
       if (child_layout.child_view == view) {
@@ -92,6 +94,11 @@
 ProposedLayout LayoutManagerBase::GetProposedLayout(
     const gfx::Size& host_size) const {
   if (cached_layout_size_ != host_size) {
+#if (DCHECK_IS_ON())
+    // This calculation must not be re-entrant.
+    DCHECK(!calculating_layout_);
+    base::AutoReset<bool> calculating_layout(&calculating_layout_, true);
+#endif
     cached_layout_size_ = host_size;
     cached_layout_ = CalculateProposedLayout(SizeBounds(host_size));
   }
diff --git a/ui/views/layout/layout_manager_base.h b/ui/views/layout/layout_manager_base.h
index 7982811e..7536240 100644
--- a/ui/views/layout/layout_manager_base.h
+++ b/ui/views/layout/layout_manager_base.h
@@ -11,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/dcheck_is_on.h"
 #include "base/macros.h"
 #include "base/optional.h"
 #include "ui/gfx/geometry/insets.h"
@@ -216,6 +217,11 @@
   // whether their bounds have changed.
   SizeBounds cached_available_size_;
 
+#if (DCHECK_IS_ON())
+  // Used to prevent GetProposedLayout() from being re-entrant.
+  mutable bool calculating_layout_ = false;
+#endif
+
   // Do some really simple caching because layout generation can cost as much
   // as 1ms or more for complex views.
   mutable base::Optional<gfx::Size> cached_minimum_size_;
diff --git a/ui/views/metadata/metadata_impl_macros.h b/ui/views/metadata/metadata_impl_macros.h
index 0ebcc776..d1c73ef 100644
--- a/ui/views/metadata/metadata_impl_macros.h
+++ b/ui/views/metadata/metadata_impl_macros.h
@@ -28,21 +28,17 @@
 
 // This will fail to compile if the property accessors aren't in the form of
 // SetXXXX and GetXXXX.
-#define ADD_PROPERTY_METADATA(property_type, property_name)                    \
-  std::unique_ptr<METADATA_PROPERTY_TYPE_INTERNAL(property_type,               \
-                                                  property_name)>              \
-      property_name##_prop = std::make_unique<METADATA_PROPERTY_TYPE_INTERNAL( \
-          property_type, property_name)>(#property_name, #property_type);      \
+#define ADD_PROPERTY_METADATA(property_type, property_name)               \
+  auto property_name##_prop =                                             \
+      std::make_unique<METADATA_PROPERTY_TYPE_INTERNAL(                   \
+          property_type, property_name)>(#property_name, #property_type); \
   AddMemberData(std::move(property_name##_prop));
 
 // This will fail to compile if the property accessor isn't in the form of
 // GetXXXX.
-#define ADD_READONLY_PROPERTY_METADATA(property_type, property_name)          \
-  std::unique_ptr<METADATA_READONLY_PROPERTY_TYPE_INTERNAL(property_type,     \
-                                                           property_name)>    \
-      property_name##_prop =                                                  \
-          std::make_unique<METADATA_READONLY_PROPERTY_TYPE_INTERNAL(          \
-              property_type, property_name)>(#property_name, #property_type); \
+#define ADD_READONLY_PROPERTY_METADATA(property_type, property_name)      \
+  auto property_name##_prop =                                             \
+      std::make_unique<METADATA_READONLY_PROPERTY_TYPE_INTERNAL(          \
+          property_type, property_name)>(#property_name, #property_type); \
   AddMemberData(std::move(property_name##_prop));
-
 #endif  // UI_VIEWS_METADATA_METADATA_IMPL_MACROS_H_
diff --git a/ui/views/metadata/metadata_types.cc b/ui/views/metadata/metadata_types.cc
index 8ed567c..1a461bee 100644
--- a/ui/views/metadata/metadata_types.cc
+++ b/ui/views/metadata/metadata_types.cc
@@ -142,5 +142,9 @@
   NOTREACHED();
 }
 
+MemberMetaDataBase::ValueStrings MemberMetaDataBase::GetValidValues() const {
+  return ValueStrings();
+}
+
 }  // namespace metadata
 }  // namespace views
diff --git a/ui/views/metadata/metadata_types.h b/ui/views/metadata/metadata_types.h
index 1d55967..af10a631 100644
--- a/ui/views/metadata/metadata_types.h
+++ b/ui/views/metadata/metadata_types.h
@@ -140,6 +140,7 @@
 // accessors to get/set the value of the member on an object.
 class VIEWS_EXPORT MemberMetaDataBase {
  public:
+  using ValueStrings = std::vector<base::string16>;
   MemberMetaDataBase(const std::string& member_name,
                      const std::string& member_type)
       : member_name_(member_name), member_type_(member_type) {}
@@ -160,6 +161,10 @@
   // Return various information flags about the property.
   virtual PropertyFlags GetPropertyFlags() const = 0;
 
+  // Return a list of valid property values as a vector of strings. An empty
+  // vector indicates that the natural limits of the underlying type applies.
+  virtual ValueStrings GetValidValues() const;
+
   const std::string& member_name() const { return member_name_; }
   const std::string& member_type() const { return member_type_; }
 
diff --git a/ui/views/metadata/property_metadata.h b/ui/views/metadata/property_metadata.h
index 3dd9043..76cb8b5c 100644
--- a/ui/views/metadata/property_metadata.h
+++ b/ui/views/metadata/property_metadata.h
@@ -78,6 +78,12 @@
     }
   }
 
+  MemberMetaDataBase::ValueStrings GetValidValues() const override {
+    if (!kIsSerializable)
+      return {};
+    return TypeConverter<TValue>::GetValidStrings();
+  }
+
   PropertyFlags GetPropertyFlags() const override {
     return kIsSerializable
                ? (PropertyFlags::kEmpty | PropertyFlags::kSerializable)
diff --git a/ui/views/metadata/type_conversion.cc b/ui/views/metadata/type_conversion.cc
index 7b51d5c..78982e2 100644
--- a/ui/views/metadata/type_conversion.cc
+++ b/ui/views/metadata/type_conversion.cc
@@ -65,6 +65,10 @@
   return base::ASCIIToUTF16(source_value ? "true" : "false");
 }
 
+ValidStrings TypeConverter<bool>::GetValidStrings() {
+  return {base::ASCIIToUTF16("false"), base::ASCIIToUTF16("true")};
+}
+
 base::string16 TypeConverter<const char*>::ToString(const char* source_value) {
   return base::UTF8ToUTF16(source_value);
 }
diff --git a/ui/views/metadata/type_conversion.h b/ui/views/metadata/type_conversion.h
index 0fc8eb0..87d79fb7 100644
--- a/ui/views/metadata/type_conversion.h
+++ b/ui/views/metadata/type_conversion.h
@@ -29,6 +29,8 @@
 namespace views {
 namespace metadata {
 
+using ValidStrings = std::vector<base::string16>;
+
 // Various metadata methods pass types either by value or const ref depending on
 // whether the types are "small" (defined as "fundamental, enum, or pointer").
 // ArgType<T> gives the appropriate type to use as an argument in such cases.
@@ -55,6 +57,7 @@
 struct TypeConverter : BaseTypeConverter<std::is_enum<T>::value> {
   static base::string16 ToString(ArgType<T> source_value);
   static base::Optional<T> FromString(const base::string16& source_value);
+  static ValidStrings GetValidStrings();
 };
 
 // Types and macros for generating enum converters ----------------------------
@@ -68,6 +71,13 @@
   explicit EnumStrings(std::vector<EnumString> init_val)
       : pairs(std::move(init_val)) {}
 
+  ValidStrings GetStringValues() const {
+    ValidStrings string_values;
+    for (const auto& pair : pairs)
+      string_values.push_back(pair.str_value);
+    return string_values;
+  }
+
   const std::vector<EnumString> pairs;
 };
 
@@ -107,6 +117,12 @@
       }                                                            \
     }                                                              \
     return base::nullopt;                                          \
+  }                                                                \
+                                                                   \
+  template <>                                                      \
+  views::metadata::ValidStrings                                    \
+  views::metadata::TypeConverter<T>::GetValidStrings() {           \
+    return GetEnumStringsInstance<T>().GetStringValues();          \
   }
 
 // String Conversions ---------------------------------------------------------
@@ -123,6 +139,7 @@
   struct VIEWS_EXPORT TypeConverter<T> : BaseTypeConverter<true> {           \
     static base::string16 ToString(ArgType<T> source_value);                 \
     static base::Optional<T> FromString(const base::string16& source_value); \
+    static ValidStrings GetValidStrings() { return {}; }                     \
   };
 
 DECLARE_CONVERSIONS(int8_t)
@@ -135,7 +152,6 @@
 DECLARE_CONVERSIONS(uint64_t)
 DECLARE_CONVERSIONS(float)
 DECLARE_CONVERSIONS(double)
-DECLARE_CONVERSIONS(bool)
 DECLARE_CONVERSIONS(const char*)
 DECLARE_CONVERSIONS(base::string16)
 DECLARE_CONVERSIONS(base::TimeDelta)
@@ -146,6 +162,15 @@
 
 #undef DECLARE_CONVERSIONS
 
+template <>
+struct VIEWS_EXPORT TypeConverter<bool> {
+  static constexpr bool is_serializable = true;
+  static bool IsSerializable() { return is_serializable; }
+  static base::string16 ToString(bool source_value);
+  static base::Optional<bool> FromString(const base::string16& source_value);
+  static ValidStrings GetValidStrings();
+};
+
 // Special Conversions for base::Optional<T> type ------------------------------
 
 VIEWS_EXPORT const base::string16& GetNullOptStr();
@@ -166,6 +191,7 @@
     auto ret = TypeConverter<T>::FromString(source_value);
     return ret ? base::make_optional(ret) : base::nullopt;
   }
+  static ValidStrings GetValidStrings() { return {}; }
 };
 
 template <typename T>
@@ -173,6 +199,7 @@
   static base::string16 ToString(const std::unique_ptr<T>& source_value);
   static base::Optional<std::unique_ptr<T>> FromString(
       const base::string16& source_value);
+  static ValidStrings GetValidStrings() { return {}; }
 };
 
 }  // namespace metadata
diff --git a/ui/views/view.cc b/ui/views/view.cc
index b6dd5a1..b7a1edbc 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -96,6 +96,13 @@
 // Same as what gtk uses.
 constexpr int kDefaultVerticalDragThreshold = 8;
 
+// The following are used to offset the keys for the callbacks associated with
+// the bounds element callbacks.
+constexpr int kXChangedKey = sizeof(int) * 0;
+constexpr int kYChangedKey = sizeof(int) * 1;
+constexpr int kWidthChangedKey = sizeof(int) * 2;
+constexpr int kHeightChangedKey = sizeof(int) * 3;
+
 // Returns the top view in |view|'s hierarchy.
 const View* GetHierarchyRoot(const View* view) {
   const View* root = view;
@@ -394,6 +401,17 @@
 
   for (ViewObserver& observer : observers_)
     observer.OnViewBoundsChanged(this);
+
+  // The property effects have already been taken into account above. No need to
+  // redo them here.
+  if (prev.x() != bounds_.x())
+    OnPropertyChanged(&bounds_ + kXChangedKey, kPropertyEffectsNone);
+  if (prev.y() != bounds_.y())
+    OnPropertyChanged(&bounds_ + kYChangedKey, kPropertyEffectsNone);
+  if (prev.width() != bounds_.width())
+    OnPropertyChanged(&bounds_ + kWidthChangedKey, kPropertyEffectsNone);
+  if (prev.height() != bounds_.height())
+    OnPropertyChanged(&bounds_ + kHeightChangedKey, kPropertyEffectsNone);
 }
 
 void View::SetSize(const gfx::Size& size) {
@@ -564,6 +582,10 @@
   return visible_ && parent_ ? parent_->IsDrawn() : false;
 }
 
+bool View::GetIsDrawn() const {
+  return IsDrawn();
+}
+
 bool View::GetEnabled() const {
   return enabled_;
 }
@@ -2243,6 +2265,34 @@
   property_changed_callbacks->Notify();
 }
 
+int View::GetX() const {
+  return x();
+}
+
+int View::GetY() const {
+  return y();
+}
+
+int View::GetWidth() const {
+  return width();
+}
+
+int View::GetHeight() const {
+  return height();
+}
+
+void View::SetWidth(int width) {
+  SetBounds(x(), y(), width, height());
+}
+
+void View::SetHeight(int height) {
+  SetBounds(x(), y(), width(), height);
+}
+
+base::string16 View::GetTooltip() const {
+  return GetTooltipText(gfx::Point());
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // View, private:
 
@@ -2427,17 +2477,17 @@
   // inherit the visibility of the owner View.
   view->UpdateLayerVisibility();
 
+  // Need to notify the layout manager because one of the callbacks below might
+  // want to know the view's new preferred size, minimum size, etc.
+  if (HasLayoutManager())
+    GetLayoutManager()->ViewAdded(this, view);
+
   if (widget) {
     const ui::NativeTheme* new_theme = view->GetNativeTheme();
     if (new_theme != old_theme)
       view->PropagateThemeChanged();
   }
 
-  // Need to notify the layout manager because one of the callbacks below might
-  // want to know the view's new preferred size, minimum size, etc.
-  if (HasLayoutManager())
-    GetLayoutManager()->ViewAdded(this, view);
-
   ViewHierarchyChangedDetails details(true, this, view, parent);
 
   for (View* v = this; v; v = v->parent_)
@@ -3171,14 +3221,20 @@
 ADD_PROPERTY_METADATA(View::FocusBehavior, FocusBehavior)
 ADD_PROPERTY_METADATA(bool, FlipCanvasOnPaintForRTLUI)
 ADD_PROPERTY_METADATA(int, Group)
+ADD_PROPERTY_METADATA(int, Height)
 ADD_PROPERTY_METADATA(int, ID)
+ADD_READONLY_PROPERTY_METADATA(bool, IsDrawn);
 ADD_READONLY_PROPERTY_METADATA(gfx::Size, MaximumSize)
 ADD_READONLY_PROPERTY_METADATA(gfx::Size, MinimumSize)
 ADD_PROPERTY_METADATA(bool, Mirrored)
 ADD_PROPERTY_METADATA(bool, NotifyEnterExitOnChild)
+ADD_READONLY_PROPERTY_METADATA(base::string16, Tooltip)
 ADD_PROPERTY_METADATA(bool, Visible)
 ADD_PROPERTY_METADATA(bool, CanProcessEventsWithinSubtree)
 ADD_PROPERTY_METADATA(bool, UseDefaultFillLayout)
+ADD_PROPERTY_METADATA(int, Width)
+ADD_PROPERTY_METADATA(int, X)
+ADD_PROPERTY_METADATA(int, Y)
 END_METADATA
 
 }  // namespace views
diff --git a/ui/views/view.h b/ui/views/view.h
index 9cf55dd5..74e3010 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1902,6 +1902,20 @@
   // function is NOT called if effects == kPropertyEffectsNone.
   void HandlePropertyChangeEffects(PropertyEffects effects);
 
+  // The following methods are used by the property access system described in
+  // the comments above. They follow the required naming convention in order to
+  // allow them to be visible via the metadata.
+  int GetX() const;
+  int GetY() const;
+  int GetWidth() const;
+  int GetHeight() const;
+  void SetWidth(int width);
+  void SetHeight(int height);
+  bool GetIsDrawn() const;
+
+  // Special property accessor used by metadata to get the ToolTip text.
+  base::string16 GetTooltip() const;
+
   //////////////////////////////////////////////////////////////////////////////
 
   // Creation and lifetime -----------------------------------------------------
diff --git a/ui/webui/resources/js/list_property_update_behavior.js b/ui/webui/resources/js/list_property_update_behavior.js
index 6ac160b..6812f541 100644
--- a/ui/webui/resources/js/list_property_update_behavior.js
+++ b/ui/webui/resources/js/list_property_update_behavior.js
@@ -21,60 +21,44 @@
 /* #export */ const ListPropertyUpdateBehavior = {
   /**
    * @param {string} propertyPath
-   * @param {function(!Object): (!Object|string)} identityGetter
+   * @param {function(!Object): string} itemUidGetter
    * @param {!Array<!Object>} updatedList
-   * @param {boolean=} identityBasedUpdate
+   * @param {boolean} uidBasedUpdate
    * @returns {boolean} True if notifySplices was called.
    */
-  updateList(
-      propertyPath, identityGetter, updatedList, identityBasedUpdate = false) {
-    return updateListProperty(
-        this, propertyPath, identityGetter, updatedList, identityBasedUpdate);
+  updateList(propertyPath, itemUidGetter, updatedList, uidBasedUpdate = false) {
+    const list = this.get(propertyPath);
+    const splices = Polymer.ArraySplice.calculateSplices(
+        updatedList.map(itemUidGetter), list.map(itemUidGetter));
+
+    splices.forEach(splice => {
+      const index = splice.index;
+      const deleteCount = splice.removed.length;
+      // Transform splices to the expected format of notifySplices().
+      // Convert !Array<string> to !Array<!Object>.
+      splice.removed = list.slice(index, index + deleteCount);
+      splice.object = list;
+      splice.type = 'splice';
+
+      const added = updatedList.slice(index, index + splice.addedCount);
+      const spliceParams = [index, deleteCount].concat(added);
+      list.splice.apply(list, spliceParams);
+    });
+
+    let updated = splices.length > 0;
+    if (!uidBasedUpdate) {
+      list.forEach((item, index) => {
+        const updatedItem = updatedList[index];
+        if (JSON.stringify(item) !== JSON.stringify(updatedItem)) {
+          this.set([propertyPath, index], updatedItem);
+          updated = true;
+        }
+      });
+    }
+
+    if (splices.length > 0) {
+      this.notifySplices(propertyPath, splices);
+    }
+    return updated;
   },
 };
-
-/**
- * @param {Object} instance
- * @param {string} propertyPath
- * @param {function(!Object): (!Object|string)} identityGetter
- * @param {!Array<!Object>} updatedList
- * @param {boolean=} identityBasedUpdate
- * @returns {boolean} True if notifySplices was called.
- */
-/* #export */ function updateListProperty(
-    instance, propertyPath, identityGetter, updatedList,
-    identityBasedUpdate = false) {
-  const list = instance.get(propertyPath);
-  const splices = Polymer.ArraySplice.calculateSplices(
-      updatedList.map(identityGetter), list.map(identityGetter));
-
-  splices.forEach(splice => {
-    const index = splice.index;
-    const deleteCount = splice.removed.length;
-    // Transform splices to the expected format of notifySplices().
-    // Convert !Array<string> to !Array<!Object>.
-    splice.removed = list.slice(index, index + deleteCount);
-    splice.object = list;
-    splice.type = 'splice';
-
-    const added = updatedList.slice(index, index + splice.addedCount);
-    const spliceParams = [index, deleteCount].concat(added);
-    list.splice.apply(list, spliceParams);
-  });
-
-  let updated = splices.length > 0;
-  if (!identityBasedUpdate) {
-    list.forEach((item, index) => {
-      const updatedItem = updatedList[index];
-      if (JSON.stringify(item) !== JSON.stringify(updatedItem)) {
-        instance.set([propertyPath, index], updatedItem);
-        updated = true;
-      }
-    });
-  }
-
-  if (splices.length > 0) {
-    instance.notifySplices(propertyPath, splices);
-  }
-  return updated;
-}
diff --git a/url/BUILD.gn b/url/BUILD.gn
index 0e3e91ee..cdcadd3 100644
--- a/url/BUILD.gn
+++ b/url/BUILD.gn
@@ -174,7 +174,10 @@
 source_set("url_test_support") {
   testonly = true
 
-  sources = [ "origin_abstract_tests.h" ]
+  sources = [
+    "gurl_abstract_tests.h",
+    "origin_abstract_tests.h",
+  ]
 
   public_deps = [
     ":url",
diff --git a/url/gurl_abstract_tests.h b/url/gurl_abstract_tests.h
new file mode 100644
index 0000000..38909be8
--- /dev/null
+++ b/url/gurl_abstract_tests.h
@@ -0,0 +1,139 @@
+// 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 URL_GURL_ABSTRACT_TESTS_H_
+#define URL_GURL_ABSTRACT_TESTS_H_
+
+// AbstractUrlTest below abstracts away differences between GURL and blink::KURL
+// by parametrizing the tests with a class that has to be derived from
+// UrlTraitsBase below.
+template <typename TConcreteUrlType>
+class UrlTraitsBase {
+ public:
+  using UrlType = TConcreteUrlType;
+  UrlTraitsBase() = default;
+
+  // Constructing an origin.
+  virtual UrlType CreateUrlFromString(base::StringPiece s) = 0;
+
+  // Accessors for origin properties.
+  virtual bool IsAboutBlank(const UrlType& url) = 0;
+  virtual bool IsAboutSrcdoc(const UrlType& url) = 0;
+
+  // This type is non-copyable and non-moveable.
+  UrlTraitsBase(const UrlTraitsBase&) = delete;
+  UrlTraitsBase& operator=(const UrlTraitsBase&) = delete;
+};
+
+// Test suite for tests that cover both url::Url and blink::SecurityUrl.
+template <typename TUrlTraits>
+class AbstractUrlTest : public testing::Test {
+  static_assert(std::is_base_of<UrlTraitsBase<typename TUrlTraits::UrlType>,
+                                TUrlTraits>::value,
+                "TUrlTraits needs to expose the right members.");
+
+ protected:
+  // Wrappers that allow tests to ignore presence of `url_traits_`.
+  //
+  // Note that calling the wrappers needs to be prefixed with `this->...` to
+  // avoid hitting: explicit qualification required to use member 'IsAboutBlank'
+  // from dependent base class.
+  using UrlType = typename TUrlTraits::UrlType;
+  UrlType CreateUrlFromString(base::StringPiece s) {
+    return url_traits_.CreateUrlFromString(s);
+  }
+  bool IsAboutBlank(const UrlType& url) {
+    return url_traits_.IsAboutBlank(url);
+  }
+  bool IsAboutSrcdoc(const UrlType& url) {
+    return url_traits_.IsAboutSrcdoc(url);
+  }
+
+ private:
+  TUrlTraits url_traits_;
+};
+
+TYPED_TEST_SUITE_P(AbstractUrlTest);
+
+TYPED_TEST_P(AbstractUrlTest, IsAboutBlankTest) {
+  // See https://tools.ietf.org/html/rfc6694 which explicitly allows
+  // `about-query` and `about-fragment` parts in about: URLs.
+  const std::string kAboutBlankUrls[] = {"about:blank", "about:blank?foo",
+                                         "about:blank/#foo",
+                                         "about:blank?foo#foo"};
+  for (const auto& input : kAboutBlankUrls) {
+    SCOPED_TRACE(testing::Message() << "Test input: " << input);
+    auto url = this->CreateUrlFromString(input);
+    EXPECT_TRUE(this->IsAboutBlank(url));
+  }
+
+  const std::string kNotAboutBlankUrls[] = {"",
+                                            "about",
+                                            "about:",
+                                            "about:blanky",
+                                            "about:blan",
+                                            "about:about:blank:",
+                                            "data:blank",
+                                            "http:blank",
+                                            "about://blank",
+                                            "about:blank/foo",
+                                            "about://:8000/blank",
+                                            "about://foo:foo@/blank",
+                                            "foo@about:blank",
+                                            "foo:bar@about:blank",
+                                            "about:blank:8000",
+                                            "about:blANk"};
+  for (const auto& input : kNotAboutBlankUrls) {
+    SCOPED_TRACE(testing::Message() << "Test input: " << input);
+    auto url = this->CreateUrlFromString(input);
+    EXPECT_FALSE(this->IsAboutBlank(url));
+  }
+}
+
+TYPED_TEST_P(AbstractUrlTest, IsAboutSrcdocTest) {
+  // See https://tools.ietf.org/html/rfc6694 which explicitly allows
+  // `about-query` and `about-fragment` parts in about: URLs.
+  //
+  // `about:srcdoc` is defined in
+  // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#about:srcdoc
+  // which refers to rfc6694 for details.
+  const std::string kAboutSrcdocUrls[] = {
+      "about:srcdoc", "about:srcdoc/", "about:srcdoc?foo", "about:srcdoc/#foo",
+      "about:srcdoc?foo#foo"};
+  for (const auto& input : kAboutSrcdocUrls) {
+    SCOPED_TRACE(testing::Message() << "Test input: " << input);
+    auto url = this->CreateUrlFromString(input);
+    EXPECT_TRUE(this->IsAboutSrcdoc(url));
+  }
+
+  const std::string kNotAboutSrcdocUrls[] = {"",
+                                             "about",
+                                             "about:",
+                                             "about:srcdocx",
+                                             "about:srcdo",
+                                             "about:about:srcdoc:",
+                                             "data:srcdoc",
+                                             "http:srcdoc",
+                                             "about:srcdo",
+                                             "about://srcdoc",
+                                             "about://srcdoc\\",
+                                             "about:srcdoc/foo",
+                                             "about://:8000/srcdoc",
+                                             "about://foo:foo@/srcdoc",
+                                             "foo@about:srcdoc",
+                                             "foo:bar@about:srcdoc",
+                                             "about:srcdoc:8000",
+                                             "about:srCDOc"};
+  for (const auto& input : kNotAboutSrcdocUrls) {
+    SCOPED_TRACE(testing::Message() << "Test input: " << input);
+    auto url = this->CreateUrlFromString(input);
+    EXPECT_FALSE(this->IsAboutSrcdoc(url));
+  }
+}
+
+REGISTER_TYPED_TEST_SUITE_P(AbstractUrlTest,
+                            IsAboutBlankTest,
+                            IsAboutSrcdocTest);
+
+#endif  // URL_GURL_ABSTRACT_TESTS_H_
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index a5d91901..e9784c78 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
+#include "url/gurl_abstract_tests.h"
 #include "url/origin.h"
 #include "url/url_canon.h"
 #include "url/url_test_utils.h"
@@ -883,70 +884,6 @@
   }
 }
 
-TEST(GURLTest, IsAboutBlank) {
-  // See https://tools.ietf.org/html/rfc6694 which explicitly allows
-  // `about-query` and `about-fragment` parts in about: URLs.
-  const std::string kAboutBlankUrls[] = {"about:blank", "about:blank?foo",
-                                         "about:blank/#foo",
-                                         "about:blank?foo#foo"};
-  for (const auto& url : kAboutBlankUrls)
-    EXPECT_TRUE(GURL(url).IsAboutBlank()) << url;
-
-  const std::string kNotAboutBlankUrls[] = {"",
-                                            "about",
-                                            "about:",
-                                            "about:blanky",
-                                            "about:blan",
-                                            "about:about:blank:",
-                                            "data:blank",
-                                            "http:blank",
-                                            "about://blank",
-                                            "about:blank/foo",
-                                            "about://:8000/blank",
-                                            "about://foo:foo@/blank",
-                                            "foo@about:blank",
-                                            "foo:bar@about:blank",
-                                            "about:blank:8000",
-                                            "about:blANk"};
-  for (const auto& url : kNotAboutBlankUrls)
-    EXPECT_FALSE(GURL(url).IsAboutBlank()) << url;
-}
-
-TEST(GURLTest, IsAboutSrcdoc) {
-  // See https://tools.ietf.org/html/rfc6694 which explicitly allows
-  // `about-query` and `about-fragment` parts in about: URLs.
-  //
-  // `about:srcdoc` is defined in
-  // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#about:srcdoc
-  // which refers to rfc6694 for details.
-  const std::string kAboutSrcdocUrls[] = {
-      "about:srcdoc", "about:srcdoc/", "about:srcdoc?foo", "about:srcdoc/#foo",
-      "about:srcdoc?foo#foo"};
-  for (const auto& url : kAboutSrcdocUrls)
-    EXPECT_TRUE(GURL(url).IsAboutSrcdoc()) << url;
-
-  const std::string kNotAboutSrcdocUrls[] = {"",
-                                             "about",
-                                             "about:",
-                                             "about:srcdocx",
-                                             "about:srcdo",
-                                             "about:about:srcdoc:",
-                                             "data:srcdoc",
-                                             "http:srcdoc",
-                                             "about:srcdo",
-                                             "about://srcdoc",
-                                             "about://srcdoc\\",
-                                             "about:srcdoc/foo",
-                                             "about://:8000/srcdoc",
-                                             "about://foo:foo@/srcdoc",
-                                             "foo@about:srcdoc",
-                                             "foo:bar@about:srcdoc",
-                                             "about:srcdoc:8000",
-                                             "about:srCDOc"};
-  for (const auto& url : kNotAboutSrcdocUrls)
-    EXPECT_FALSE(GURL(url).IsAboutSrcdoc()) << url;
-}
-
 TEST(GURLTest, EqualsIgnoringRef) {
   const struct {
     const char* url_a;
@@ -1055,4 +992,17 @@
   EXPECT_FALSE(default_port_origin.IsSameOriginWith(resolved_origin));
 }
 
+class GURLTestTraits final : public UrlTraitsBase<GURL> {
+ public:
+  UrlType CreateUrlFromString(base::StringPiece s) override { return GURL(s); }
+
+  bool IsAboutBlank(const UrlType& url) override { return url.IsAboutBlank(); }
+
+  bool IsAboutSrcdoc(const UrlType& url) override {
+    return url.IsAboutSrcdoc();
+  }
+};
+
+INSTANTIATE_TYPED_TEST_SUITE_P(GURL, AbstractUrlTest, GURLTestTraits);
+
 }  // namespace url
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
index a0bd66e..fe24d68 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
@@ -29,6 +29,8 @@
 import androidx.annotation.Nullable;
 import androidx.core.content.FileProvider;
 
+import dalvik.system.DexFile;
+
 import org.chromium.base.BuildInfo;
 import org.chromium.base.BundleUtils;
 import org.chromium.base.CommandLine;
@@ -42,10 +44,13 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.NativeLibraryPreloader;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskTraits;
 import org.chromium.components.browser_ui.contacts_picker.ContactsPickerDialog;
 import org.chromium.components.browser_ui.photo_picker.DecoderServiceHost;
 import org.chromium.components.browser_ui.photo_picker.ImageDecoder;
@@ -88,6 +93,7 @@
 import org.chromium.weblayer_private.settings.SettingsFragmentImpl;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
@@ -317,6 +323,8 @@
             }
         });
 
+        performDexFixIfNecessary(packageInfo);
+
         TraceEvent.end("WebLayer init");
     }
 
@@ -916,6 +924,40 @@
         return getClientApplicationName();
     }
 
+    /*
+     * Android O MR1 has a bug where bg-dexopt-job will break optimized dex files for isolated
+     * splits. This leads to *very* slow startup on those devices. To mitigate this, we attempt
+     * to force a dex compile if necessary.
+     */
+    private static void performDexFixIfNecessary(PackageInfo packageInfo) {
+        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) {
+            return;
+        }
+
+        PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> {
+            ApplicationInfo appInfo = packageInfo.applicationInfo;
+            String[] splitNames = ApiHelperForO.getSplitNames(appInfo);
+            for (int i = 0; i < splitNames.length; i++) {
+                String splitName = splitNames[i];
+                // WebLayer depends on the "weblayer" split and "chrome" split (if running in
+                // Monochrome).
+                if (!splitName.equals("chrome") && !splitName.equals("weblayer")) {
+                    continue;
+                }
+                String splitDir = appInfo.splitSourceDirs[i];
+                try {
+                    if (DexFile.isDexOptNeeded(splitDir)) {
+                        String cmd = String.format("cmd package compile -r shared --split %s %s",
+                                new File(splitDir).getName(), packageInfo.packageName);
+                        Runtime.getRuntime().exec(cmd);
+                    }
+                } catch (IOException e) {
+                    Log.e(TAG, "Error fixing dex files.", e);
+                }
+            }
+        });
+    }
+
     @NativeMethods
     interface Natives {
         void setRemoteDebuggingEnabled(boolean enabled);
diff --git a/weblayer/browser/subresource_filter_browsertest.cc b/weblayer/browser/subresource_filter_browsertest.cc
index 5995af45..b0f77ef 100644
--- a/weblayer/browser/subresource_filter_browsertest.cc
+++ b/weblayer/browser/subresource_filter_browsertest.cc
@@ -4,7 +4,6 @@
 
 #include "base/json/json_reader.h"
 #include "build/build_config.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
 #include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
 #include "components/subresource_filter/content/browser/ruleset_service.h"
@@ -16,7 +15,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "weblayer/browser/browser_process.h"
-#include "weblayer/browser/host_content_settings_map_factory.h"
 #include "weblayer/browser/subresource_filter_client_impl.h"
 #include "weblayer/browser/tab_impl.h"
 #include "weblayer/grit/weblayer_resources.h"
@@ -91,7 +89,8 @@
  protected:
   void SetRulesetToDisallowURLsWithPathSuffix(const std::string& suffix) {
     subresource_filter::testing::TestRulesetPair test_ruleset_pair;
-    test_ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix(
+    subresource_filter::testing::TestRulesetCreator test_ruleset_creator;
+    test_ruleset_creator.CreateRulesetToDisallowURLsWithPathSuffix(
         suffix, &test_ruleset_pair);
 
     subresource_filter::testing::TestRulesetPublisher test_ruleset_publisher(
@@ -115,9 +114,6 @@
                 ->client());
     client_impl->set_database_manager_for_testing(std::move(database_manager));
   }
-
- private:
-  subresource_filter::testing::TestRulesetCreator test_ruleset_creator_;
 };
 
 // Tests that the ruleset service is available.
@@ -298,68 +294,6 @@
   EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
 }
 
-IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
-                       ContentSettingsAllowlist_DoNotActivate) {
-  auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
-
-  GURL test_url(
-      embedded_test_server()->GetURL("/frame_with_included_script.html"));
-
-  ASSERT_NO_FATAL_FAILURE(
-      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
-  ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
-
-  NavigateAndWaitForCompletion(test_url, shell());
-  EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
-
-  content::WebContentsConsoleObserver console_observer(web_contents);
-  console_observer.SetPattern(subresource_filter::kActivationConsoleMessage);
-
-  // Simulate explicitly allowlisting via content settings.
-  HostContentSettingsMap* settings_map =
-      HostContentSettingsMapFactory::GetForBrowserContext(
-          web_contents->GetBrowserContext());
-  settings_map->SetContentSettingDefaultScope(
-      test_url, test_url, ContentSettingsType::ADS, CONTENT_SETTING_ALLOW);
-
-  NavigateAndWaitForCompletion(test_url, shell());
-  EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
-
-  // No message for allowlisted url.
-  EXPECT_TRUE(console_observer.messages().empty());
-}
-
-IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
-                       ContentSettingsAllowlistGlobal_DoNotActivate) {
-  auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
-
-  GURL test_url(
-      embedded_test_server()->GetURL("/frame_with_included_script.html"));
-
-  ASSERT_NO_FATAL_FAILURE(
-      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
-  ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
-
-  NavigateAndWaitForCompletion(test_url, shell());
-  EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
-
-  content::WebContentsConsoleObserver console_observer(web_contents);
-  console_observer.SetPattern(subresource_filter::kActivationConsoleMessage);
-
-  // Simulate globally allowing ads via content settings.
-  HostContentSettingsMap* settings_map =
-      HostContentSettingsMapFactory::GetForBrowserContext(
-          web_contents->GetBrowserContext());
-  settings_map->SetDefaultContentSetting(ContentSettingsType::ADS,
-                                         CONTENT_SETTING_ALLOW);
-
-  NavigateAndWaitForCompletion(test_url, shell());
-  EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
-
-  // No message for loads that are not activated.
-  EXPECT_TRUE(console_observer.messages().empty());
-}
-
 #if defined(OS_ANDROID)
 // Test that the ads blocked infobar is presented when visiting a page where the
 // subresource filter blocks resources from being loaded and is removed when
diff --git a/weblayer/browser/subresource_filter_client_impl.cc b/weblayer/browser/subresource_filter_client_impl.cc
index a99f17ce..ba3eebb 100644
--- a/weblayer/browser/subresource_filter_client_impl.cc
+++ b/weblayer/browser/subresource_filter_client_impl.cc
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
-#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
 #include "components/subresource_filter/content/browser/ruleset_service.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
 #include "components/subresource_filter/core/common/activation_decision.h"
@@ -19,7 +18,6 @@
 #include "content/public/browser/render_frame_host.h"
 #include "weblayer/browser/browser_process.h"
 #include "weblayer/browser/safe_browsing/safe_browsing_service.h"
-#include "weblayer/browser/subresource_filter_profile_context_factory.h"
 
 #if defined(OS_ANDROID)
 #include "components/safe_browsing/android/remote_database_manager.h"
@@ -55,12 +53,7 @@
 #if defined(OS_ANDROID)
       web_contents_(web_contents),
 #endif
-      database_manager_(GetDatabaseManagerFromSafeBrowsingService()),
-      profile_interaction_manager_(
-          std::make_unique<subresource_filter::ProfileInteractionManager>(
-              web_contents,
-              SubresourceFilterProfileContextFactory::GetForBrowserContext(
-                  web_contents->GetBrowserContext()))) {
+      database_manager_(GetDatabaseManagerFromSafeBrowsingService()) {
 }
 
 SubresourceFilterClientImpl::~SubresourceFilterClientImpl() = default;
@@ -94,6 +87,16 @@
 #endif
 }
 
+subresource_filter::mojom::ActivationLevel
+SubresourceFilterClientImpl::OnPageActivationComputed(
+    content::NavigationHandle* navigation_handle,
+    subresource_filter::mojom::ActivationLevel initial_activation_level,
+    subresource_filter::ActivationDecision* decision) {
+  DCHECK(navigation_handle->IsInMainFrame());
+
+  return initial_activation_level;
+}
+
 void SubresourceFilterClientImpl::OnAdsViolationTriggered(
     content::RenderFrameHost* rfh,
     subresource_filter::mojom::AdsViolation triggered_violation) {}
@@ -103,9 +106,4 @@
   return database_manager_;
 }
 
-subresource_filter::ProfileInteractionManager*
-SubresourceFilterClientImpl::GetProfileInteractionManager() {
-  return profile_interaction_manager_.get();
-}
-
 }  // namespace weblayer
diff --git a/weblayer/browser/subresource_filter_client_impl.h b/weblayer/browser/subresource_filter_client_impl.h
index cceb5d20..1debbf2 100644
--- a/weblayer/browser/subresource_filter_client_impl.h
+++ b/weblayer/browser/subresource_filter_client_impl.h
@@ -43,13 +43,15 @@
 
   // SubresourceFilterClient:
   void ShowNotification() override;
+  subresource_filter::mojom::ActivationLevel OnPageActivationComputed(
+      content::NavigationHandle* navigation_handle,
+      subresource_filter::mojom::ActivationLevel initial_activation_level,
+      subresource_filter::ActivationDecision* decision) override;
   void OnAdsViolationTriggered(
       content::RenderFrameHost* rfh,
       subresource_filter::mojom::AdsViolation triggered_violation) override;
   const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
   GetSafeBrowsingDatabaseManager() override;
-  subresource_filter::ProfileInteractionManager* GetProfileInteractionManager()
-      override;
   void OnReloadRequested() override;
 
   // Sets the SafeBrowsingDatabaseManager instance used to |database_manager|.
@@ -68,8 +70,6 @@
   std::unique_ptr<subresource_filter::ContentSubresourceFilterThrottleManager>
       throttle_manager_;
   scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
-  std::unique_ptr<subresource_filter::ProfileInteractionManager>
-      profile_interaction_manager_;
 };
 
 }  // namespace weblayer
diff --git a/weblayer/renderer/content_renderer_client_impl.cc b/weblayer/renderer/content_renderer_client_impl.cc
index 4cbac11..1f89a88 100644
--- a/weblayer/renderer/content_renderer_client_impl.cc
+++ b/weblayer/renderer/content_renderer_client_impl.cc
@@ -12,7 +12,6 @@
 #include "components/error_page/common/error.h"
 #include "components/grit/components_scaled_resources.h"
 #include "components/js_injection/renderer/js_communication.h"
-#include "components/no_state_prefetch/common/prerender_types.mojom.h"
 #include "components/no_state_prefetch/common/prerender_url_loader_throttle.h"
 #include "components/no_state_prefetch/renderer/no_state_prefetch_client.h"
 #include "components/no_state_prefetch/renderer/prerender_helper.h"
@@ -198,10 +197,8 @@
 }
 
 bool ContentRendererClientImpl::IsPrefetchOnly(
-    content::RenderFrame* render_frame,
-    const blink::WebURLRequest& request) {
-  return prerender::PrerenderHelper::GetPrerenderMode(render_frame) ==
-         prerender::mojom::PrerenderMode::kPrefetchOnly;
+    content::RenderFrame* render_frame) {
+  return prerender::PrerenderHelper::IsPrerendering(render_frame);
 }
 
 bool ContentRendererClientImpl::DeferMediaLoad(
diff --git a/weblayer/renderer/content_renderer_client_impl.h b/weblayer/renderer/content_renderer_client_impl.h
index bec5c28..c37fa76 100644
--- a/weblayer/renderer/content_renderer_client_impl.h
+++ b/weblayer/renderer/content_renderer_client_impl.h
@@ -45,8 +45,7 @@
       std::vector<std::unique_ptr<::media::KeySystemProperties>>* key_systems)
       override;
   void SetRuntimeFeaturesDefaultsBeforeBlinkInitialization() override;
-  bool IsPrefetchOnly(content::RenderFrame* render_frame,
-                      const blink::WebURLRequest& request) override;
+  bool IsPrefetchOnly(content::RenderFrame* render_frame) override;
   bool DeferMediaLoad(content::RenderFrame* render_frame,
                       bool has_played_media_before,
                       base::OnceClosure closure) override;